diff --git a/.circleci/config.yml b/.circleci/config.yml index c54498cd..bcbada44 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,7 +11,7 @@ jobs: - restore_cache: keys: - - v2-dependencies-{{ checksum "requirements.txt" }} + - v2-dependencies-{{ checksum "requirements-dev.txt" }} - v2-dependencies- - run: @@ -52,23 +52,27 @@ jobs: - run: name: install dependencies 2 command: | - pip install -r requirements.txt + pip install -r requirements-dev.txt - save_cache: paths: - ./venv - key: v2-dependencies-{{ checksum "requirements.txt" }} + key: v2-dependencies-{{ checksum "requirements-dev.txt" }} + - run: + name: version + command: | + protoc --version + python -c "import google.protobuf as gp;print(gp.__version__)" + - run: name: run tests command: | - export PYTHONPATH=src - python setup.py unittests + python -m pytest _unittests - run: name: wheel command: | - export PYTHONPATH=src python setup.py bdist_wheel mkdir -p test-reports/dist cp dist/*.whl test-reports/dist diff --git a/.github/workflows/black-ruff.yml b/.github/workflows/black-ruff.yml new file mode 100644 index 00000000..9a047430 --- /dev/null +++ b/.github/workflows/black-ruff.yml @@ -0,0 +1,16 @@ +name: Black + Ruff Format Checker +on: [push, pull_request] +jobs: + black-format-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: psf/black@stable + with: + options: "--diff --check" + src: "." + ruff-format-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: chartboost/ruff-action@v1 diff --git a/.github/workflows/check-urls.yml b/.github/workflows/check-urls.yml new file mode 100644 index 00000000..f856f316 --- /dev/null +++ b/.github/workflows/check-urls.yml @@ -0,0 +1,47 @@ +name: Check URLs + +on: + pull_request: + branches: [main] + schedule: + # ┌───────────── minute (0 - 59) + # │ ┌───────────── hour (0 - 23) + # │ │ ┌───────────── day of the month (1 - 31) + # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) + # │ │ │ │ │ + # │ │ │ │ │ + # │ │ │ │ │ + # * * * * * + - cron: '30 1 * * 0' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: urls-checker-code + uses: urlstechie/urlchecker-action@master + with: + subfolder: teachpyx + file_types: .md,.py,.rst,.ipynb + print_all: false + timeout: 5 + retry_count# : 3 + # exclude_urls: https://dumps.wikimedia.org/other/pageviews/%Y/%Y-%m/pageviews-%Y%m%d-%H0000.gz,https://dumps.wikimedia.org/frwiki/latest/latest-all-titles-in-ns0.gz + exclude_patterns: https://dumps.wikimedia.org/ + # force_pass : true + + - name: urls-checker-docs + uses: urlstechie/urlchecker-action@master + with: + subfolder: _doc + file_types: .md,.py,.rst,.ipynb + print_all: false + timeout: 5 + retry_count# : 3 + exclude_urls: https://hal.archives-ouvertes.fr/hal-00990252/document,https://github.com/onnx/models/raw/main/vision/classification/mobilenet/model/mobilenetv2-12.onnx,https://arxiv.org/ftp/arxiv/papers/1510/1510.04863.pdf,https://hal.science/hal-01125940 + exclude_patterns: https://www.data.gouv.fr/fr/datasets/r/e3d83ab3-dc52-4c99-abaf-8a38050cc68c,https://github.com/onnx/models/raw/main/vision/classification/mobilenet/model/mobilenetv2-12.onnx + # force_pass : true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..bea1259d --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,61 @@ +name: "Code Scanning - Action" + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + # ┌───────────── minute (0 - 59) + # │ ┌───────────── hour (0 - 23) + # │ │ ┌───────────── day of the month (1 - 31) + # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) + # │ │ │ │ │ + # │ │ │ │ │ + # │ │ │ │ │ + # * * * * * + - cron: '30 1 * * 0' + +jobs: + CodeQL-Build: + # CodeQL runs on ubuntu-latest, windows-latest, and macos-latest + runs-on: ubuntu-latest + + permissions: + # required for all workflows + security-events: write + + # only required for workflows in private repositories + actions: read + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java, ruby + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below). + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # ✏️ If the Autobuild fails above, remove it and uncomment the following + # three lines and modify them (or add more) to build your code if your + # project uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000..185a7faa --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,93 @@ +name: Documentation and Code Coverage + +on: + push: + pull_request: + types: + - closed + branches: + - main + +jobs: + run: + name: Build documentation on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - uses: tlylt/install-graphviz@v1 + + - name: Install pandoc + run: sudo apt-get install -y pandoc protobuf-compiler + + - name: Install requirements + run: python -m pip install -r requirements.txt + + - name: Install requirements dev + run: python -m pip install -r requirements-dev.txt + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: protobuf version + run: | + protoc --version + python -c "import google.protobuf as gp;print(gp.__version__)" + + - name: Generate coverage report + run: | + pip install pytest + pip install pytest-cov + export PYTHONPATH=. + pytest --cov=./teachpyx/ --cov-report=xml --durations=10 --ignore-glob=**LONG*.py --ignore-glob=**notebook*.py + export PYTHONPATH= + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + - name: Install + run: python setup.py install + + - name: Copy license + run: cp LICENSE* ./_doc + - name: Copy changelogs + run: cp CHANGELOGS* ./_doc + + - name: Documentation + run: python -m sphinx ./_doc ./dist/html -n -w doc.txt + + - name: Summary + run: cat doc.txt + + - name: Check for errors and warnings + run: | + if [[ $(grep ERROR doc.txt) ]]; then + echo "Documentation produces errors." + grep ERROR doc.txt + exit 1 + fi + if [[ $(grep WARNING doc.txt) ]]; then + echo "Documentation produces warnings." + grep WARNING doc.txt + exit 1 + fi + + - uses: actions/upload-artifact@v3 + with: + path: ./dist/html/** diff --git a/.github/workflows/rstcheck.yml b/.github/workflows/rstcheck.yml new file mode 100644 index 00000000..9642e5dd --- /dev/null +++ b/.github/workflows/rstcheck.yml @@ -0,0 +1,27 @@ +name: RST Check + +on: [push, pull_request] + +jobs: + build_wheels: + name: rstcheck ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install requirements + run: python -m pip install -r requirements.txt + + - name: Install rstcheck + run: python -m pip install sphinx tomli rstcheck[toml,sphinx] + + - name: rstcheck + run: rstcheck -r _doc teachpyx diff --git a/.github/workflows/wheels-any.yml b/.github/workflows/wheels-any.yml new file mode 100644 index 00000000..67fa88c0 --- /dev/null +++ b/.github/workflows/wheels-any.yml @@ -0,0 +1,29 @@ +name: Build Any Wheel + +on: + push: + branches: + - main + - 'releases/**' + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: build wheel + run: python -m pip wheel . + + - uses: actions/upload-artifact@v3 + with: + path: ./teachpyx*.whl diff --git a/.gitignore b/.gitignore index 27d03d5f..3187bf20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,282 +1,30 @@ -################# -## Eclipse -################# - -*.pydevproject -.project -.metadata -bin/ -tmp/ -_virtualenv/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.classpath -.settings/ -.loadpath -*.pyproj -dummy.py - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# CDT-specific -.cproject - -# PDT-specific -.buildpath - - -################# -## Visual Studio -################# - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.sln.docstates - -# Build results - -[Dd]ebug/ -[Rr]elease/ -x64/ -build/ -[Bb]in/ -[Oo]bj/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj +*.dot +*.dylib +*.prof +*.pyc +*.pyd +*.so +*.bin *.log -*.vspscc -*.vssscc -.builds -*.pidb -*.log -*.scc - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -*.ncrunch* -.*crunch*.local.xml - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.Publish.xml -*.pubxml - -# NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line -#packages/ - -# Windows Azure Build Output -csx -*.build.csdef - -# Windows Store app package directory -AppPackages/ - -# Others -sql/ -*.Cache -ClientBin/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.[Pp]ublish.xml -*.pfx -*.publishsettings - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -App_Data/*.mdf -App_Data/*.ldf - -############# -## Windows detritus -############# - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Mac crap -.DS_Store - - -############# -## Python -############# - -*.py[co] - -# Packages -*.egg -*.egg-info -dist/ -build/ -eggs/ -parts/ -var/ -sdist/ -develop-eggs/ -__pycache__/ -.installed.cfg - -# Installer logs -pip-log.txt - -# Unit test / coverage reports .coverage -.tox - -#Translations -*.mo - -#Mr Developer -.mr.developer.cfg - -# py* packages +.eggs/* +_cache/* +build/* +dist/* +*egg-info/* +onnxruntime_profile* +prof temp_* -out_* -*/sphinxdoc/source/index_* -*/sphinxdoc/source/readme.* -*/sphinxdoc/source/LICENSE.txt -*/sphinxdoc/source/filechanges.* -version.txt -_doc/sphinxdoc/source/python_template/*box.html -_doc/sphinxdoc/source/python_template/*toc.html -_doc/sphinxdoc/source/teachpyx/ -_doc/sphinxdoc/source/coverage/* -*/sphinxdoc/source/all*.rst -_doc/sphinxdoc/source/notebooks/* -*/sphinxdoc/source/gynotebooks/* -_doc/sphinxdoc/source/gyexamples/* -_doc/sphinxdoc/source/examples/* -_doc/sphinxdoc/source/gallery/* -_doc/sphinxdoc/source/gallerynb/* -build_help.bat -_doc/sphinxdoc/source/blog/*.rst -_doc/sphinxdoc/source/blog/rss.xml -_doc/sphinxdoc/source/phdoc_templates/*toc.html -_doc/sphinxdoc/source/phdoc_templates/*box.html -_doc/sphinxdoc/source/blog/feed-icon*.png -_doc/sphinxdoc/source/_static/reveal.js/* -_doc/notebooks/.ipynb_checkpoints/* -dist_module27/* -auto_*.bat -auto_*.sh -auto_*.py -auto_*.xml -auto_*.db3 -_doc/sphinxdoc/source/_static/require.js -_doc/sphinxdoc/require.js -ex.* -m.temp -_doc/notebooks/*/.ipynb_checkpoints -_doc/notebooks/nlp/frwiki-latest-all-titles-in-ns0 -_doc/notebooks/nlp/sample*.txt -_doc/notebooks/nlp/completion.prof -_doc/notebooks/nlp/profile.png -_doc/notebooks/nlp/completion.dot -_doc/notebooks/nlp/completion.png -_doc/notebooks/nlp/completion.pstat -_unittests/run_unittests.py.out -*.err -_doc/sphinxdoc/source/_static/style_notebook_snippet.css -_todo/programme/data.bin -_todo/programme/info.bin -_doc/sphinxdoc/data.bin -_doc/sphinxdoc/info.bin -_doc/notebooks/Untitled.ipynb -_doc/sphinxdoc/source/c_gui/images/ren.py -_doc/sphinxdoc/source/nbcov.png -_doc/notebooks/python/include/* -_doc/notebooks/python/bin/* -_doc/notebooks/python/schema_pb2.py -_doc/notebooks/python/schema.proto -_doc/notebooks/python/protoc-*.zip -_doc/sphinxdoc/source/_temp_custom_run_script_* -_doc/sphinxdoc/source/_static/viz.js +essai.txt +.ipynb_checkpoints +_doc/CHANGELOGS.rst +_doc/LICENSE.txt +_doc/auto_examples/* +_doc/examples/*.proto +_doc/examples/schema_pb2.py +_doc/examples/plot_*.png +_doc/examples/plot_*.xlsx +_doc/examples/data/*.optimized.onnx +_doc/examples/*.html +_doc/_static/require.js +_doc/_static/viz.js diff --git a/.landscape.yml b/.landscape.yml deleted file mode 100644 index 2288fb96..00000000 --- a/.landscape.yml +++ /dev/null @@ -1,18 +0,0 @@ -doc-warnings: true -test-warnings: false -strictness: veryhigh -max-line-length: 120 -autodetect: true -pep8: full -python-targets: 3 -requirements: - - requirement.txt -ignore-paths: - - _unittests - - _doc - - src - - dist - - build -ignore-patterns: - - .*Parser\.py$ - - .*Lexer\.py$ diff --git a/.local.jenkins.lin.yml b/.local.jenkins.lin.yml index 4e2a4208..f50eca8b 100644 --- a/.local.jenkins.lin.yml +++ b/.local.jenkins.lin.yml @@ -9,8 +9,8 @@ virtualenv: install: - $PYINT -m pip install --upgrade pip - - $PYINT -m pip install --upgrade --no-cache-dir --no-deps --index http://localhost:8067/simple/ jyquickhelper pyquickhelper pandas_streaming --extra-index-url=https://pypi.python.org/simple/ - - $PYINT -m pip install -r requirements.txt + - $PYINT -m pip install --upgrade --no-cache-dir --no-deps --index http://localhost:8067/simple/ pyquickhelper pandas_streaming --extra-index-url=https://pypi.python.org/simple/ + - $PYINT -m pip install -r requirements-dev.txt - $PYINT --version - $PYINT -m pip freeze diff --git a/.local.jenkins.win.yml b/.local.jenkins.win.yml deleted file mode 100644 index cffcc11f..00000000 --- a/.local.jenkins.win.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: python -python: - - { PATH: "{{replace(Python39, '\\', '\\\\')}}", VERSION: 3.9, DIST: std, PYTHONPATH: src } -virtualenv: - - path: {{ospathjoin(root_path, pickname("%NAME_JENKINS%", project_name + "_%VERSION%_%DIST%_%NAME%"), "_venv")}} -install: - - pip install --upgrade pip - - pip install --no-cache-dir --no-deps --index http://localhost:8067/simple/ pyquickhelper pyensae pymmails pymyinstall pyrsslocal - - pip install -r requirements.txt - - pip freeze - - pip freeze > pip_freeze.txt -script: - - { CMD: "python -X faulthandler -X showrefcount -u setup.py unittests", NAME: "UT" } - - { CMD: "python -X faulthandler -X showrefcount -u setup.py unittests_LONG", NAME: "UT_LONG", TIMEOUT: 3600 } -after_script: - - python -u setup.py bdist_wheel - - if [ ${DIST} != "conda" and ${NAME} == "UT" ] then copy dist\*.whl {{root_path}}\..\..\local_pypi\local_pypi_server fi -documentation: - - if [ ${NAME} == "UT" ] then python -u setup.py build_sphinx fi - - if [ ${NAME} == "UT" ] then xcopy /E /C /I /Y _doc\sphinxdoc\build\html dist\html fi - - if [ ${NAME} == "UT" ] then xcopy /E /C /I /Y _doc\sphinxdoc\build\elatex\*.pdf dist\html fi diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b83388aa..00000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -dist: focal -sudo: true -language: python -env: - - SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=disk -matrix: - include: - - python: 3.10 - addons: - - apt: - - packages: - - graphviz -before_install: - -install: - - pip install -r requirements.txt - - export PYTHONPATH=src -script: - - python setup.py unittests diff --git a/CHANGELOGS.rst b/CHANGELOGS.rst new file mode 100644 index 00000000..6c121ad6 --- /dev/null +++ b/CHANGELOGS.rst @@ -0,0 +1,7 @@ +Change Logs +=========== + +0.2.0 ++++++ + +* :pr:`7`: refactoring diff --git a/HISTORY.rst b/HISTORY.rst deleted file mode 100644 index 8ca1e733..00000000 --- a/HISTORY.rst +++ /dev/null @@ -1,22 +0,0 @@ - -.. _l-HISTORY: - -======= -History -======= - -current - 2021-01-01 - 0.00Mb -============================= - -0.0.0 - 2021-01-01 - 0.00Mb -=========================== - -* `14`: Aborder la notation f"" (2019-12-22) -* `10`: talk about warnings (2018-09-23) -* `6`: remove double entries in index (website) (2018-09-23) -* `9`: move pandas_groupby_nan to pandas_streaming (2018-05-17) -* `8`: talk about protobuf (2018-04-21) -* `7`: talk about serialization (2018-04-20) -* `5`: fix .. only:: html in readme.rst (2018-03-29) -* `2`: finish the migration of latex (2017-06-10) -* `1`: completed completion (2016-09-25) diff --git a/README.rst b/README.rst index c30fa027..02535df6 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,4 @@ -.. image:: https://travis-ci.com/sdpython/teachpyx.svg?branch=master - :target: https://app.travis-ci.com/github/sdpython/teachpyx - :alt: Build status - .. image:: https://ci.appveyor.com/api/projects/status/5jl303wl14dtesl0?svg=true :target: https://ci.appveyor.com/project/sdpython/teachpyx :alt: Build Status Windows @@ -24,25 +20,13 @@ :alt: GitHub Issues :target: https://github.com/sdpython/teachpyx/issues -.. image:: http://www.xavierdupre.fr/app/teachpyx/helpsphinx/_images/nbcov.png - :target: http://www.xavierdupre.fr/app/teachpyx/helpsphinx/all_notebooks_coverage.html - :alt: Notebook Coverage - .. image:: https://img.shields.io/github/repo-size/sdpython/teachpyx :target: https://github.com/sdpython/teachpyx/ :alt: size -.. _l-README: - -teachpyx -======== +teachpyx: programmation python +============================== -Programmation *Python* en français. -A usage pédagogique. La documentation du module +Programmation *Python* en français. A usage pédagogique. La +`documentation `_ du module est construite pour un cours de programmation. - -**Links:** - -* `GitHub/teachpyx `_ -* `documentation `_ -* `Blog `_ diff --git a/_doc/sphinxdoc/source/_static/git_logo.png b/_doc/_static/git_logo.png similarity index 100% rename from _doc/sphinxdoc/source/_static/git_logo.png rename to _doc/_static/git_logo.png diff --git a/_doc/sphinxdoc/source/_static/project_ico.ico b/_doc/_static/project_ico.ico similarity index 100% rename from _doc/sphinxdoc/source/_static/project_ico.ico rename to _doc/_static/project_ico.ico diff --git a/_doc/sphinxdoc/source/_static/project_ico.png b/_doc/_static/project_ico.png similarity index 100% rename from _doc/sphinxdoc/source/_static/project_ico.png rename to _doc/_static/project_ico.png diff --git a/_doc/sphinxdoc/source/_static/project_ico_small.png b/_doc/_static/project_ico_small.png similarity index 100% rename from _doc/sphinxdoc/source/_static/project_ico_small.png rename to _doc/_static/project_ico_small.png diff --git a/_doc/api/classique.rst b/_doc/api/classique.rst new file mode 100644 index 00000000..13461ee4 --- /dev/null +++ b/_doc/api/classique.rst @@ -0,0 +1,5 @@ +examples.construction_classique +=============================== + +.. automodule:: teachpyx.examples.construction_classique + :members: diff --git a/_doc/api/index.rst b/_doc/api/index.rst new file mode 100644 index 00000000..ddc7589b --- /dev/null +++ b/_doc/api/index.rst @@ -0,0 +1,6 @@ +Code inclus dans cette librairie +================================ + +.. toctree:: + + classique diff --git a/_doc/sphinxdoc/source/c_classes/classes.rst b/_doc/c_classes/classes.rst similarity index 98% rename from _doc/sphinxdoc/source/c_classes/classes.rst rename to _doc/c_classes/classes.rst index f1179cb4..b5fa33ef 100644 --- a/_doc/sphinxdoc/source/c_classes/classes.rst +++ b/_doc/c_classes/classes.rst @@ -5,8 +5,6 @@ Classes ======= -.. index:: classe - .. contents:: :local: :depth: 2 @@ -77,7 +75,7 @@ colonnes, les coefficients de la matrice. Cette matrice inclut aussi des méthodes comme des opérations entre deux matrices telles que l'addition, la soustraction, la multiplication ou des opérations sur elle-même comme l'inversion, la transposition, la diagonalisation. - + Cette liste n'est pas exhaustive, elle illustre ce que peut être une classe "matrice" - représentation informatique d'un objet "matrice" -, un type complexe incluant des informations de types variés (entier @@ -175,7 +173,7 @@ Méthodes Les méthodes sont des fonctions qui sont associées de manière explicite à une classe. Elles ont comme particularité un accès privilégié aux données de la classe elle-même. -Ces données ou *attributs* sont définis plus loin. Les méthodes sont en +Ces données ou *attributs* sont définis plus loin. Les méthodes sont en fait des fonctions pour lesquelles la liste des paramètres contient obligatoirement un paramètre explicite qui est l'instance de la classe à laquelle cette méthode est associée. Ce paramètre @@ -562,8 +560,8 @@ création d'une instance. Ils contiennent des informations sur l'instance. (voir paragraphe :ref:`par_class_liste_attribut`. * - ``__doc__`` - Contient un commentaire associé à la classe - (voir paragraphe :ref:`par_class_commentaire`. - + (voir paragraphe :ref:`par_class_commentaire`. + L'attribut ``__class__`` contient lui même d'autres d'attributs : .. list-table:: @@ -656,16 +654,13 @@ Le plus utilisé est .. index:: dir -La fonction `dir `_ -permet aussi d'obtenir des informations +La fonction :epkg:`dir` permet aussi d'obtenir des informations sur la classe. Cette fonction appliquée à la classe ou à une instance retourne l'ensemble de la liste des attributs et des méthodes. L'exemple suivant utilise la fonction -`dir `_ -avant et après l'appel de la méthode ``meth``. Etant donné +:epkg:`dir` avant et après l'appel de la méthode ``meth``. Etant donné que cette méthode ajoute un attribut, la fonction -`dir `_ -retourne une liste plus longue après l'appel. +:epkg:`dir` retourne une liste plus longue après l'appel. .. runpython:: :showcode: @@ -681,7 +676,7 @@ retourne une liste plus longue après l'appel. print(dir(a)) # affiche ['__doc__', '__module__', 'meth', 'y'] print(dir(essai_class)) # affiche ['__doc__', '__module__', 'meth'] -La fonction `dir `_ +La fonction :epkg:`dir` appliquée à la classe elle-même retourne une liste qui inclut les méthodes et les attributs déjà déclarés. Elle n'inclut pas ceux qui sont déclarés dans une méthode jamais exécutée @@ -918,7 +913,7 @@ l'instruction ``print`` affiche un nombre complexe sous la forme :math:`a+ i b`. print(c3) # affiche 1.000000 + 1.000000 i Il existe de nombreux opérateurs qu'il est possible de définir. -La table :ref:`operateur_classe` présente les plus utilisés. +La table :ref:`opérateurs et classes ` présente les plus utilisés. Parmi ceux-là, on peut s'attarder sur les opérateurs ``__getitem__`` et ``__setitem__``, ils redéfinissent l'opérateur ``[]`` permettant d'accéder à un élément d'une liste ou d'un dictionnaire. @@ -931,7 +926,7 @@ et ``__setitem__`` de manière à pouvoir accéder aux coordonnées de la classe ``point_espace`` qui définit un point dans l'espace. En règle générale, lorsque les indices ne sont pas corrects, ces deux opérateurs lèvent l'exception ``IndexError`` -(voir le chapitre :ref:`chap_exception`. +(voir le chapitre :ref:`chap_exception`). .. runpython:: :showcode: @@ -971,7 +966,7 @@ Par le biais de l'exception ``IndexError``, les expressions le programme par un message comme celui qui suit obtenu après l'interprétation de ``print(a[4])`` : -.. _operator_classe: +.. _operateur_classe: .. list-table:: :widths: 5 10 @@ -1022,7 +1017,7 @@ l'interprétation de ``print(a[4])`` : - Opérateurs appelés pour les opérations ``+``, ``/``, ``*``, ``-``, ``**``, ``<``, ``<`` * - ``__iadd__(self,x)``, ``__idiv__(self,x)``, ``__imul__(self,x)``, - ``__isub__(self,x)``, ``__ipow__(self,x)``, ``__ilshift__(self, x)`` + ``__isub__(self,x)``, ``__ipow__(self,x)``, ``__ilshift__(self, x)`` ``__irshift__(self, x)`` - Opérateurs appelés pour les opérations ``+=``, ``/=``, ``*=``, ``-=``, ``**=``, ``<<=``, ``>>=`` @@ -1502,6 +1497,8 @@ du corps de ``essai_class``. .. _classe_proprietes_par: +.. _exemple_point_xyz: + Propriétés ---------- @@ -1565,8 +1562,6 @@ qui multiplie les parties réelle et imaginaire par un nombre réel positif de manière à ce que le nombre complexe ait le module demandé. On procède de même pour la propriété ``arg``. -.. _exemple_point_xyz: - La propriété ``conj`` retourne quant à elle le conjugué du nombre complexe mais la réciproque n'est pas prévue. On ne peut affecter une valeur à ``conj``. @@ -1806,7 +1801,7 @@ Pour effectivement copier les attributs dont le type est une classe, la première option - la plus simple - est de remplacer la fonction ``copy`` par la fonction ``deepcopy``. Le comportement de cette fonction dans le cas des classes est le même que dans le cas des -listes comme l'explique la remarque :ref:`copy_deepopy_remarque_`. +listes comme l'explique la remarque :ref:`copy_deepopy_remarque`. La seconde solution, rarement utilisée, est d'utiliser l'opérateur ``__copy__`` et ainsi écrire le code associé à la copie des attributs de la classe. @@ -2541,7 +2536,7 @@ définition reste inchangée. Lorsqu'une classe *B* hérite de la classe *A* et redéfinit une méthode de la classe *A* portant le même nom, on dit qu'elle surcharge cette méthode. S'il n'est pas explicitement précisé qu'on fait appel à une méthode d'une classe donnée, c'est toujours la méthode surchargée qui est exécutée. - + Syntaxe ------- @@ -2594,7 +2589,7 @@ On obtient le résultat suivant : .. _remarque_method_resolution_order: -La rubrique `Method Resolution Order `_ +La rubrique :epkg:`Method Resolution Order` indique la liste des héritages successifs qui ont mené à la classe ``piece_tres_truquee``. Cette rubrique indique aussi que, lorsqu'on appelle une méthode de la classe ``piece_tres_truquee``, si elle n'est pas redéfinie dans cette classe, @@ -2622,7 +2617,7 @@ classe hérite d'une autre comme le montre l'exemple suivant. print(piece_normale in piece_tres_truquee.__bases__) # affiche False print(piece_truquee in piece_tres_truquee.__bases__) # affiche True -La fonction `issubclass `_ +La fonction :epkg:`issubclass` permet d'obtenir un résultat équivalent. ``issubclass(A,B)`` indique si la classe ``A`` hérite directement ou indirectement de la classe ``B``. Le paragraphe :ref:`fonction_issubclass_paragraphe` revient sur cette fonction. @@ -2730,8 +2725,8 @@ de la classe fille afin que cette attribut existe pour la classe fille. .. _heritage_classe_sens_par: -Sens de l'héritage ------------------- +Sens de l'héritage (2) +---------------------- Il n'est pas toujours évident de concevoir le sens d'un héritage. En mathématique, le carré est un rectangle dont les côtés sont @@ -2886,7 +2881,7 @@ méthode ``calcul`` qui, par défaut, sera celle de la classe ``A``. Cette information est disponible via la fonction ``help`` appliquée à la classe ``C``. C'est dans ce genre de situations que l'information apportée par la section -`Method Resolution Order `_ +:epkg:`Method Resolution Order` est importante. :: @@ -2952,7 +2947,7 @@ Fonctions issubclass et isinstance .. index:: issubclass -La fonction `issubclass `_ +La fonction :epkg:`issubclass` permet de savoir si une classe hérite d'une autre. :: @@ -3133,8 +3128,7 @@ la chaîne de caractères ``s`` et non à la troisième ligne du programme. def decouper(self,nb): l = [] for i in range (0,nb) : - f = fromage (self.poids/nb, \ - self.couleur, self.odeur) + f = fromage(self.poids/nb, self.couleur, self.odeur) l.append(f) return l @@ -3149,12 +3143,11 @@ la chaîne de caractères ``s`` et non à la troisième ligne du programme. poids = self.poids + f.poids couleur = [0,0,0] for i in range (0,3) : - couleur [i] = (self.couleur [i] * self.poids \ - + f.couleur [i] * f.poids) / poids - odeur = (self.odeur * self.poids + \ - f.odeur * f.poids) / poids - couleur = ( couleur [0], couleur [1], couleur [2]) - return fromage (poids, couleur, odeur) + couleur [i] = (self.couleur [i] * self.poids + + f.couleur[i] * f.poids) / poids + odeur = (self.odeur * self.poids + f.odeur * f.poids) / poids + couleur = (couleur[0], couleur[1], couleur[2]) + return fromage(poids, couleur, odeur) class gruyere(fromage): def __init__ (self,p) : @@ -3244,11 +3237,11 @@ Constructions classiques .. _paragraphe_fonction_variable_classe: -Héritage --------- +Sens de l'héritage (1) +---------------------- Le premier exemple est classique puisqu'il reprend le programme du -paragraphe :ref:`paragraphe_fonction_variable` +paragraphe :ref:`fonction comme paramètre ` pour le réécrire avec des classes et éviter de passer des fonctions comme paramètre d'une autre fonction. La première classe définit le module des suivantes. La méthode ``calcul`` n'accepte qu'un @@ -3370,8 +3363,7 @@ suivre le schéma qui suit. class MatriceList (Matrice) : def __init__ (self,lin,col,coef): - Matrice.__init__ (self, \ - lin, col, coef) + Matrice.__init__ (self, lin, col, coef) #... def __getitem__ (self, i,j) : #... @@ -3381,8 +3373,7 @@ suivre le schéma qui suit. class MatriceDict (Matrice) : def __init__ (self,lin,col,coef): - Matrice.__init__ (self, \ - lin, col, coef) + Matrice.__init__ (self, lin, col, coef) #... def __getitem__ (self, i,j) : #... diff --git a/_doc/sphinxdoc/source/c_classes/index.rst b/_doc/c_classes/index.rst similarity index 82% rename from _doc/sphinxdoc/source/c_classes/index.rst rename to _doc/c_classes/index.rst index c0458fdb..3f56ce20 100644 --- a/_doc/sphinxdoc/source/c_classes/index.rst +++ b/_doc/c_classes/index.rst @@ -7,3 +7,5 @@ Classes :maxdepth: 2 classes + questions + diff --git a/_doc/c_classes/questions.rst b/_doc/c_classes/questions.rst new file mode 100644 index 00000000..ba444b6a --- /dev/null +++ b/_doc/c_classes/questions.rst @@ -0,0 +1,177 @@ + +######### +Questions +######### + +.. contents:: + :local: + +.. _blog-class-ou-fonction: + +C'est obligé d'utiliser les classes ? +====================================== + +*Monsieur, c'est obligé d'utiliser les classes ?* +C'est une question qu'on me pose chaque année +lors des projets informatiques +et je réponds chaque année que non, les classes +ne sont pas obligatoires mais qu'elles ont le don +de simplifier l'écriture des programmes. +Le lanage :epkg:`Python` propose une des syntaxes +les plus explicites par rapport à d'autres langages +car il n'y a pas de paramètres cachés. +Le programme suivant calcule la somme et le produit +de deux entiers stockés dans un dictionnaire. + +.. runpython:: + :showcode: + + def deux_entiers_somme(de): + return de['i1'] + de['i2'] + + def deux_entiers_multiplication(de): + return de['i1'] * de['i2'] + + de = {'i1': 3, 'i2': 2} + s = deux_entiers_somme(de) + m = deux_entiers_multiplication(de) + print(s, m) + +Les deux fonctions ne sont applicables qu'à deux entiers. +Il paraît normal de les préfixer avec *deux_entiers* +pour signifier à celui qui les utiliser que ça ne sert +à rien de les utiliser pour autre chose. +Les classes permettent de regrouper formellement +ces deux fonctions. + +.. runpython:: + :showcode: + + class DeuxEntiers: + + def somme(de): + return de['i1'] + de['i2'] + + def multiplication(de): + return de['i1'] * de['i2'] + + de = {'i1': 3, 'i2': 2} + s = DeuxEntiers.somme(de) # _ --> . + m = DeuxEntiers.multiplication(de) # _ --> . + print(s, m) + +On a juste remplacé le signe ``_`` par ``.`` qui signifie +que la fonction cherchée est dans la classe qui précède ``.``. +Comme les deux entiers en questions sont toujours liés +aux fonctions qui les manipulent, il paraît normal de les +inclure dans la classe. + +.. runpython:: + :showcode: + + class DeuxEntiers: + + def __init__(self, de): # on accroche les données à la classe + self.de = de + + def somme(self): + return self.de['i1'] + self.de['i2'] + + def multiplication(self): + return self.de['i1'] * self.de['i2'] + + de = DeuxEntiers({'i1': 3, 'i2': 2}) + s = DeuxEntiers.somme(de) + m = DeuxEntiers.multiplication(de) + print(s, m) + +Comme le concept a beaucoup plu aux informaticiens, +ils ont cherché à simplifier l'appel aux fonctions qu'ils +ont appelé des *méthodes* : + +.. runpython:: + :showcode: + + class DeuxEntiers: + + def __init__(self, de): + self.de = de + + def somme(self): + return self.de['i1'] + self.de['i2'] + + def multiplication(self): + return self.de['i1'] * self.de['i2'] + + de = DeuxEntiers({'i1': 3, 'i2': 2}) + s = de.somme() # disparition de DeuxEntiers + m = de.multiplication() # disparition de DeuxEntiers + print(s, m) + +.. index:: attribut + +Ensuite, ils se sont penchés sur la simplification de la représentation +des deux entiers ``{'i1': 3, 'i2': 2}``. Et s'ils étaient considérés comme +des variables de la classe qui ont été renommés en *attributs*. + +.. runpython:: + :showcode: + + class DeuxEntiers: + + def __init__(self, i1, i2): + self.i1 = i1 # plus de dictionnaire + self.i2 = i2 + + def somme(self): + return self.i1 + self.i2 # plus de dictionnaire + + def multiplication(self): + return self.i1 * self.i2 # plus de dictionnaire + + de = DeuxEntiers(3, 2) # plus de dictionnaire + s = de.somme() + m = de.multiplication() + print(s, m) + +Les classes permettent de regrouper formellement +les fonctions qui ne s'appliquent toujours aux mêmes +données. Plus encore, ce nouveau concept a permis d'en +introduire un autre, l':ref:`par_classe_heritage`, qui +permet de réutiliser certaines fonctions, d'en remplacer +d'autres et d'en ajouter pour une autre situation. + +.. runpython:: + :showcode: + + class DeuxEntiers: + + def __init__(self, i1, i2): + self.i1 = i1 + self.i2 = i2 + + def somme(self): + return self.i1 + self.i2 + + def multiplication(self): + return self.i1 * self.i2 + + class DeuxEntiersModifies(DeuxEntiers): # héritage + + def multiplication(self): + return abs(self.i1 * self.i2) # modifié + + def division(self): + return abs(self.i1 / self.i2) # ajouté + + de = DeuxEntiersModifies(-3, 2) + s = de.somme() + m = de.multiplication() + d = de.division() + print(s, m, d) + +Cela peut paraît anodin mais la grande majorité des +programmeurs utilisent majoritairement les classes +une fois qu'ils les ont découvertes car elles +permettent d'organiser le code informatique +en bloc logique. diff --git a/_doc/c_data/dataframes.rst b/_doc/c_data/dataframes.rst new file mode 100644 index 00000000..6d19cfeb --- /dev/null +++ b/_doc/c_data/dataframes.rst @@ -0,0 +1,5 @@ +========== +Dataframes +========== + +*à compléter* diff --git a/_doc/sphinxdoc/source/c_data/index.rst b/_doc/c_data/index.rst similarity index 100% rename from _doc/sphinxdoc/source/c_data/index.rst rename to _doc/c_data/index.rst diff --git a/_doc/c_data/matrices.rst b/_doc/c_data/matrices.rst new file mode 100644 index 00000000..a892a1a7 --- /dev/null +++ b/_doc/c_data/matrices.rst @@ -0,0 +1,6 @@ +================ +Calcul matriciel +================ + +*à compléter* + diff --git a/_doc/sphinxdoc/source/c_exception/exception.rst b/_doc/c_exception/exception.rst similarity index 99% rename from _doc/sphinxdoc/source/c_exception/exception.rst rename to _doc/c_exception/exception.rst index e32ea6ea..ad929219 100644 --- a/_doc/sphinxdoc/source/c_exception/exception.rst +++ b/_doc/c_exception/exception.rst @@ -37,8 +37,9 @@ Attraper toutes les erreurs Une exception est un objet qui indique que le programme ne peut continuer son exécution. Le type de l'exception donne une indication sur le type de l'erreur rencontrée. L'exception contient généralement un message plus détaillé. -Toutes les exceptions hérite du type -`Exception `_. +Toutes les exceptions hérite des types :class:`BaseException` +pour les exceptions définies par le langage et :class:`Exception` pour +les exceptions définies par l'utilisateur. On décide par exemple qu'on veut rattraper toutes les erreurs du programme et afficher un message d'erreur. Le programme suivant appelle diff --git a/_doc/sphinxdoc/source/c_exception/exception_ext.rst b/_doc/c_exception/exception_ext.rst similarity index 95% rename from _doc/sphinxdoc/source/c_exception/exception_ext.rst rename to _doc/c_exception/exception_ext.rst index f17baa7d..720d9486 100644 --- a/_doc/sphinxdoc/source/c_exception/exception_ext.rst +++ b/_doc/c_exception/exception_ext.rst @@ -5,8 +5,8 @@ Usage ===== -Pile d'appel -============ +Pile d'appel ou call stack +========================== La `pile d'appel `_ (ou *pile d'exécution* ou *call stack*) mémorise les appels de fonctions. @@ -113,8 +113,8 @@ Conventions Erreur ou code d'erreur +++++++++++++++++++++++ -.. todoext:: - :title: terminer la section Erreur ou code d'erreur +*à compléter* - parler aussi de coûts d'une exception, - libération des ressources +* erreur ou code d'erreur +* coûts d'une exception +* libération des ressources diff --git a/_doc/sphinxdoc/source/c_exception/index.rst b/_doc/c_exception/index.rst similarity index 100% rename from _doc/sphinxdoc/source/c_exception/index.rst rename to _doc/c_exception/index.rst diff --git a/_doc/sphinxdoc/source/c_exception/warning.rst b/_doc/c_exception/warning.rst similarity index 72% rename from _doc/sphinxdoc/source/c_exception/warning.rst rename to _doc/c_exception/warning.rst index 00e53fa4..d7854513 100644 --- a/_doc/sphinxdoc/source/c_exception/warning.rst +++ b/_doc/c_exception/warning.rst @@ -1,14 +1,16 @@ .. _l-warning: -======= -Warning -======= +================== +Warning et logging +================== .. index:: warning -Les `warning `_ -ne sont pas des erreurs mais des soupçons d'erreurs. +Warnings +======== + +Les *warnings* ne sont pas des erreurs mais des soupçons d'erreurs. Le programme peut continuer mais il est possible qu'il s'arrête un peu plus tard et la cause pourrait être un *warning* déclenché un peu plus tôt. @@ -24,10 +26,9 @@ finalement supprimée. Tout code s'appuyant encore sur cette fonction provoquera une erreur. Générer un warning -================== +------------------ -Le module `warnings `_ -permet de lancer un *warning* comme ceci : +Le module :mod:`warnings` permet de lancer un *warning* comme ceci : .. runpython:: :showcode: @@ -47,7 +48,7 @@ les trier. warnings.warn("Warning d'un certain lancé !", UserWarning) Intercepter un warning -====================== +---------------------- Les *warning* sont parfois très agaçants car il s'insère dans les sorties du programme qui deviennent moins lisibles. Il serait @@ -122,7 +123,7 @@ des tests unitaires. print("warning {0} : {1}".format(i, w)) Warning personnalisé -==================== +-------------------- Comme pour les exceptions, il est possible de définir ses propres *warning* en héritant d'un *warning* en particulier. @@ -136,3 +137,25 @@ Comme pour les exceptions, il est possible de définir ses propres pass warnings.warn("mon warning", MonWarning) + +Logging +======= + +Les logs enregistrent des événements qu'un programme produit. +Ils sont utilisées pour comprendre des erreurs que celui-ci produit. +Le premier réflexe est d'insérer des instructions `print` pour +afficher des résultats intermédiaires pour déterminer le premier +endroit où une erreur se produit. Et puis on les enlève car ils +rendent les résultats illisibles dans une masse d'informations +inutiles lorsque tout se passe bien. + +Il faut voir les logs comme des `print` silencieux qu'un développeur +peut activer s'il a besoin de traces d'exécution pour débugger. +C'est aussi pratique pour comprendre ce qu'il se passe sur un problème +créer par un utilisateur d'un programme qu'on développe. L'utilisateur +peut activer les logs et les transmettre à celui qui peut les comprendre. +Les logs sont indispensables à tout site web. Ils enregistrent toutes les +connexions et permettent vérifier rapidement si un site est attaqué ou pas. + +Les logs sont une fonctionnalité présente dans la plupart des langages. +En python, c'est le module :mod:`logging` qui l'implémente. diff --git a/_doc/sphinxdoc/source/c_gui/images/after.png b/_doc/c_gui/images/after.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/after.png rename to _doc/c_gui/images/after.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apachein.png b/_doc/c_gui/images/apachein.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apachein.png rename to _doc/c_gui/images/apachein.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apant0.png b/_doc/c_gui/images/apant0.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apant0.png rename to _doc/c_gui/images/apant0.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apant1.png b/_doc/c_gui/images/apant1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apant1.png rename to _doc/c_gui/images/apant1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apant2.png b/_doc/c_gui/images/apant2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apant2.png rename to _doc/c_gui/images/apant2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apant3.png b/_doc/c_gui/images/apant3.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apant3.png rename to _doc/c_gui/images/apant3.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apant4.png b/_doc/c_gui/images/apant4.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apant4.png rename to _doc/c_gui/images/apant4.png diff --git a/_doc/sphinxdoc/source/c_gui/images/apant5.png b/_doc/c_gui/images/apant5.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/apant5.png rename to _doc/c_gui/images/apant5.png diff --git a/_doc/sphinxdoc/source/c_gui/images/arbo.png b/_doc/c_gui/images/arbo.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/arbo.png rename to _doc/c_gui/images/arbo.png diff --git a/_doc/sphinxdoc/source/c_gui/images/bbette.png b/_doc/c_gui/images/bbette.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/bbette.png rename to _doc/c_gui/images/bbette.png diff --git a/_doc/sphinxdoc/source/c_gui/images/bbette2.png b/_doc/c_gui/images/bbette2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/bbette2.png rename to _doc/c_gui/images/bbette2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/bind.png b/_doc/c_gui/images/bind.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/bind.png rename to _doc/c_gui/images/bind.png diff --git a/_doc/sphinxdoc/source/c_gui/images/boost.png b/_doc/c_gui/images/boost.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/boost.png rename to _doc/c_gui/images/boost.png diff --git a/_doc/sphinxdoc/source/c_gui/images/boostp.png b/_doc/c_gui/images/boostp.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/boostp.png rename to _doc/c_gui/images/boostp.png diff --git a/_doc/sphinxdoc/source/c_gui/images/bouton.png b/_doc/c_gui/images/bouton.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/bouton.png rename to _doc/c_gui/images/bouton.png diff --git a/_doc/sphinxdoc/source/c_gui/images/bouton2.png b/_doc/c_gui/images/bouton2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/bouton2.png rename to _doc/c_gui/images/bouton2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/bouton3.png b/_doc/c_gui/images/bouton3.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/bouton3.png rename to _doc/c_gui/images/bouton3.png diff --git a/_doc/sphinxdoc/source/c_gui/images/can.png b/_doc/c_gui/images/can.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/can.png rename to _doc/c_gui/images/can.png diff --git a/_doc/sphinxdoc/source/c_gui/images/check.png b/_doc/c_gui/images/check.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/check.png rename to _doc/c_gui/images/check.png diff --git a/_doc/sphinxdoc/source/c_gui/images/check2.png b/_doc/c_gui/images/check2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/check2.png rename to _doc/c_gui/images/check2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/cmds.png b/_doc/c_gui/images/cmds.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/cmds.png rename to _doc/c_gui/images/cmds.png diff --git a/_doc/sphinxdoc/source/c_gui/images/cmds26.png b/_doc/c_gui/images/cmds26.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/cmds26.png rename to _doc/c_gui/images/cmds26.png diff --git a/_doc/sphinxdoc/source/c_gui/images/combo1.png b/_doc/c_gui/images/combo1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/combo1.png rename to _doc/c_gui/images/combo1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/combo2.png b/_doc/c_gui/images/combo2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/combo2.png rename to _doc/c_gui/images/combo2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/comm1.png b/_doc/c_gui/images/comm1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/comm1.png rename to _doc/c_gui/images/comm1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/comm2.png b/_doc/c_gui/images/comm2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/comm2.png rename to _doc/c_gui/images/comm2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/config.png b/_doc/c_gui/images/config.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/config.png rename to _doc/c_gui/images/config.png diff --git a/_doc/sphinxdoc/source/c_gui/images/entree.png b/_doc/c_gui/images/entree.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/entree.png rename to _doc/c_gui/images/entree.png diff --git a/_doc/sphinxdoc/source/c_gui/images/essai.png b/_doc/c_gui/images/essai.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/essai.png rename to _doc/c_gui/images/essai.png diff --git a/_doc/sphinxdoc/source/c_gui/images/fenpers.png b/_doc/c_gui/images/fenpers.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/fenpers.png rename to _doc/c_gui/images/fenpers.png diff --git a/_doc/sphinxdoc/source/c_gui/images/focus.png b/_doc/c_gui/images/focus.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/focus.png rename to _doc/c_gui/images/focus.png diff --git a/_doc/sphinxdoc/source/c_gui/images/frame.png b/_doc/c_gui/images/frame.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/frame.png rename to _doc/c_gui/images/frame.png diff --git a/_doc/sphinxdoc/source/c_gui/images/graphviz.png b/_doc/c_gui/images/graphviz.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/graphviz.png rename to _doc/c_gui/images/graphviz.png diff --git a/_doc/sphinxdoc/source/c_gui/images/grid1.png b/_doc/c_gui/images/grid1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/grid1.png rename to _doc/c_gui/images/grid1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/hhw.png b/_doc/c_gui/images/hhw.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/hhw.png rename to _doc/c_gui/images/hhw.png diff --git a/_doc/sphinxdoc/source/c_gui/images/inte.png b/_doc/c_gui/images/inte.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/inte.png rename to _doc/c_gui/images/inte.png diff --git a/_doc/sphinxdoc/source/c_gui/images/label.png b/_doc/c_gui/images/label.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/label.png rename to _doc/c_gui/images/label.png diff --git a/_doc/sphinxdoc/source/c_gui/images/label2.png b/_doc/c_gui/images/label2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/label2.png rename to _doc/c_gui/images/label2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/ligne.png b/_doc/c_gui/images/ligne.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/ligne.png rename to _doc/c_gui/images/ligne.png diff --git a/_doc/sphinxdoc/source/c_gui/images/ligne26.png b/_doc/c_gui/images/ligne26.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/ligne26.png rename to _doc/c_gui/images/ligne26.png diff --git a/_doc/sphinxdoc/source/c_gui/images/list1.png b/_doc/c_gui/images/list1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/list1.png rename to _doc/c_gui/images/list1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/list2.png b/_doc/c_gui/images/list2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/list2.png rename to _doc/c_gui/images/list2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/listboxs.png b/_doc/c_gui/images/listboxs.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/listboxs.png rename to _doc/c_gui/images/listboxs.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mainloop.png b/_doc/c_gui/images/mainloop.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mainloop.png rename to _doc/c_gui/images/mainloop.png diff --git a/_doc/sphinxdoc/source/c_gui/images/menu.png b/_doc/c_gui/images/menu.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/menu.png rename to _doc/c_gui/images/menu.png diff --git a/_doc/sphinxdoc/source/c_gui/images/menut.png b/_doc/c_gui/images/menut.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/menut.png rename to _doc/c_gui/images/menut.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql1.png b/_doc/c_gui/images/mysql1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql1.png rename to _doc/c_gui/images/mysql1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql2.png b/_doc/c_gui/images/mysql2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql2.png rename to _doc/c_gui/images/mysql2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql3.png b/_doc/c_gui/images/mysql3.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql3.png rename to _doc/c_gui/images/mysql3.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql4.png b/_doc/c_gui/images/mysql4.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql4.png rename to _doc/c_gui/images/mysql4.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql5.png b/_doc/c_gui/images/mysql5.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql5.png rename to _doc/c_gui/images/mysql5.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql6.png b/_doc/c_gui/images/mysql6.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql6.png rename to _doc/c_gui/images/mysql6.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql7.png b/_doc/c_gui/images/mysql7.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql7.png rename to _doc/c_gui/images/mysql7.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysql8.png b/_doc/c_gui/images/mysql8.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysql8.png rename to _doc/c_gui/images/mysql8.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysqlodbc.png b/_doc/c_gui/images/mysqlodbc.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysqlodbc.png rename to _doc/c_gui/images/mysqlodbc.png diff --git a/_doc/sphinxdoc/source/c_gui/images/mysqlodbc2.png b/_doc/c_gui/images/mysqlodbc2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/mysqlodbc2.png rename to _doc/c_gui/images/mysqlodbc2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/odbc.png b/_doc/c_gui/images/odbc.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/odbc.png rename to _doc/c_gui/images/odbc.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pack1.png b/_doc/c_gui/images/pack1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pack1.png rename to _doc/c_gui/images/pack1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pack2.png b/_doc/c_gui/images/pack2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pack2.png rename to _doc/c_gui/images/pack2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pass.png b/_doc/c_gui/images/pass.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pass.png rename to _doc/c_gui/images/pass.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pcmd.png b/_doc/c_gui/images/pcmd.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pcmd.png rename to _doc/c_gui/images/pcmd.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pcmd2.png b/_doc/c_gui/images/pcmd2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pcmd2.png rename to _doc/c_gui/images/pcmd2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pcmd26.png b/_doc/c_gui/images/pcmd26.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pcmd26.png rename to _doc/c_gui/images/pcmd26.png diff --git a/_doc/sphinxdoc/source/c_gui/images/popt.png b/_doc/c_gui/images/popt.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/popt.png rename to _doc/c_gui/images/popt.png diff --git a/_doc/sphinxdoc/source/c_gui/images/profile.png b/_doc/c_gui/images/profile.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/profile.png rename to _doc/c_gui/images/profile.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pydoc_image.png b/_doc/c_gui/images/pydoc_image.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pydoc_image.png rename to _doc/c_gui/images/pydoc_image.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pydoch.png b/_doc/c_gui/images/pydoch.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pydoch.png rename to _doc/c_gui/images/pydoch.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pyform1.png b/_doc/c_gui/images/pyform1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pyform1.png rename to _doc/c_gui/images/pyform1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/pyscripter.png b/_doc/c_gui/images/pyscripter.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/pyscripter.png rename to _doc/c_gui/images/pyscripter.png diff --git a/_doc/sphinxdoc/source/c_gui/images/radio.png b/_doc/c_gui/images/radio.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/radio.png rename to _doc/c_gui/images/radio.png diff --git a/_doc/sphinxdoc/source/c_gui/images/radio2.png b/_doc/c_gui/images/radio2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/radio2.png rename to _doc/c_gui/images/radio2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/rawinput.png b/_doc/c_gui/images/rawinput.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/rawinput.png rename to _doc/c_gui/images/rawinput.png diff --git a/_doc/sphinxdoc/source/c_gui/images/reper.png b/_doc/c_gui/images/reper.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/reper.png rename to _doc/c_gui/images/reper.png diff --git a/_doc/sphinxdoc/source/c_gui/images/reper26.png b/_doc/c_gui/images/reper26.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/reper26.png rename to _doc/c_gui/images/reper26.png diff --git a/_doc/sphinxdoc/source/c_gui/images/runs.png b/_doc/c_gui/images/runs.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/runs.png rename to _doc/c_gui/images/runs.png diff --git a/_doc/sphinxdoc/source/c_gui/images/saisie1.png b/_doc/c_gui/images/saisie1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/saisie1.png rename to _doc/c_gui/images/saisie1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/saisie2.png b/_doc/c_gui/images/saisie2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/saisie2.png rename to _doc/c_gui/images/saisie2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/scite1.png b/_doc/c_gui/images/scite1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/scite1.png rename to _doc/c_gui/images/scite1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/scite2.png b/_doc/c_gui/images/scite2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/scite2.png rename to _doc/c_gui/images/scite2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/scite226.png b/_doc/c_gui/images/scite226.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/scite226.png rename to _doc/c_gui/images/scite226.png diff --git a/_doc/sphinxdoc/source/c_gui/images/seqev.png b/_doc/c_gui/images/seqev.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/seqev.png rename to _doc/c_gui/images/seqev.png diff --git a/_doc/sphinxdoc/source/c_gui/images/sql1.png b/_doc/c_gui/images/sql1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/sql1.png rename to _doc/c_gui/images/sql1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn1.png b/_doc/c_gui/images/svn1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn1.png rename to _doc/c_gui/images/svn1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn10a.png b/_doc/c_gui/images/svn10a.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn10a.png rename to _doc/c_gui/images/svn10a.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn10b.png b/_doc/c_gui/images/svn10b.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn10b.png rename to _doc/c_gui/images/svn10b.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn11a.png b/_doc/c_gui/images/svn11a.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn11a.png rename to _doc/c_gui/images/svn11a.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn11b.png b/_doc/c_gui/images/svn11b.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn11b.png rename to _doc/c_gui/images/svn11b.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn12_.png b/_doc/c_gui/images/svn12_.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn12_.png rename to _doc/c_gui/images/svn12_.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn2ex.png b/_doc/c_gui/images/svn2ex.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn2ex.png rename to _doc/c_gui/images/svn2ex.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn3r.png b/_doc/c_gui/images/svn3r.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn3r.png rename to _doc/c_gui/images/svn3r.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn4f.png b/_doc/c_gui/images/svn4f.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn4f.png rename to _doc/c_gui/images/svn4f.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn5f.png b/_doc/c_gui/images/svn5f.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn5f.png rename to _doc/c_gui/images/svn5f.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn61.png b/_doc/c_gui/images/svn61.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn61.png rename to _doc/c_gui/images/svn61.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn72.png b/_doc/c_gui/images/svn72.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn72.png rename to _doc/c_gui/images/svn72.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn8n.png b/_doc/c_gui/images/svn8n.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn8n.png rename to _doc/c_gui/images/svn8n.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn8nn.png b/_doc/c_gui/images/svn8nn.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn8nn.png rename to _doc/c_gui/images/svn8nn.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn9a.png b/_doc/c_gui/images/svn9a.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn9a.png rename to _doc/c_gui/images/svn9a.png diff --git a/_doc/sphinxdoc/source/c_gui/images/svn9b.png b/_doc/c_gui/images/svn9b.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/svn9b.png rename to _doc/c_gui/images/svn9b.png diff --git a/_doc/sphinxdoc/source/c_gui/images/text1.png b/_doc/c_gui/images/text1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/text1.png rename to _doc/c_gui/images/text1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/threadim1.png b/_doc/c_gui/images/threadim1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/threadim1.png rename to _doc/c_gui/images/threadim1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/threadim2.png b/_doc/c_gui/images/threadim2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/threadim2.png rename to _doc/c_gui/images/threadim2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/tixfile.png b/_doc/c_gui/images/tixfile.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/tixfile.png rename to _doc/c_gui/images/tixfile.png diff --git a/_doc/sphinxdoc/source/c_gui/images/view.png b/_doc/c_gui/images/view.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/view.png rename to _doc/c_gui/images/view.png diff --git a/_doc/sphinxdoc/source/c_gui/images/wiki1.png b/_doc/c_gui/images/wiki1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/wiki1.png rename to _doc/c_gui/images/wiki1.png diff --git a/_doc/sphinxdoc/source/c_gui/images/wiki2.png b/_doc/c_gui/images/wiki2.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/wiki2.png rename to _doc/c_gui/images/wiki2.png diff --git a/_doc/sphinxdoc/source/c_gui/images/wiki3.png b/_doc/c_gui/images/wiki3.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/wiki3.png rename to _doc/c_gui/images/wiki3.png diff --git a/_doc/sphinxdoc/source/c_gui/images/wiki4.png b/_doc/c_gui/images/wiki4.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/wiki4.png rename to _doc/c_gui/images/wiki4.png diff --git a/_doc/sphinxdoc/source/c_gui/images/wiki5.png b/_doc/c_gui/images/wiki5.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/wiki5.png rename to _doc/c_gui/images/wiki5.png diff --git a/_doc/sphinxdoc/source/c_gui/images/wiki6.png b/_doc/c_gui/images/wiki6.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/wiki6.png rename to _doc/c_gui/images/wiki6.png diff --git a/_doc/sphinxdoc/source/c_gui/images/window1.png b/_doc/c_gui/images/window1.png similarity index 100% rename from _doc/sphinxdoc/source/c_gui/images/window1.png rename to _doc/c_gui/images/window1.png diff --git a/_doc/sphinxdoc/source/c_gui/index.rst b/_doc/c_gui/index.rst similarity index 100% rename from _doc/sphinxdoc/source/c_gui/index.rst rename to _doc/c_gui/index.rst diff --git a/_doc/sphinxdoc/source/c_gui/tkinter.rst b/_doc/c_gui/tkinter.rst similarity index 86% rename from _doc/sphinxdoc/source/c_gui/tkinter.rst rename to _doc/c_gui/tkinter.rst index 392bb372..a10b7d22 100644 --- a/_doc/sphinxdoc/source/c_gui/tkinter.rst +++ b/_doc/c_gui/tkinter.rst @@ -24,26 +24,27 @@ une fonction. C'est comme si le programme avait une multitude de points d'entrée. Il existe plusieurs modules permettant d'exploiter les interfaces graphiques. -Le plus simple est le module `tkinter `_ +Le plus simple est le module :epkg:`tkinter` présent lors de l'installation du langage *Python*. Ce module est simple mais limité. -Le module `wxPython `_ est une alternative plus riche +Le module :epkg:`wxPython` est une alternative plus riche mais il faut vérifier que sa dernière mise à jour est assez récente. La plus connue est `PyQt5 `_ (ou `PyQt4 `_). -Le module `tkinter `_ +Le module :epkg:`tkinter` fait partie de la distribution standard de *Python* et sera disponible dans toutes les verions de *Python*. Visuellement, *tkinter* est moins *joli* que d'autres extensions mais il vaut mieux vérifier la fréquence des mises à jour de leur code source avant d'en choisir une `github/wxPython `_ `github/PyQt5 `_. -La licence de `wxPython `_ est plus souple. +La licence de :epkg:`wxPython` est plus souple. D'autres alternatives sont disponibles à -`Other Graphical User Interface Packages `_. +`Other Graphical User Interface Packages +`_. Le fonctionnement des interfaces graphiques sous un module ou un autre est presque identique. C'est pourquoi ce chapitre n'en présentera qu'un seul, -le module `tkinter `_. +le module :epkg:`tkinter`. Pour d'autres modules, les noms de classes changent mais la logique reste la même : il s'agit d'associer des événements à des parties du programme *Python*. @@ -53,7 +54,17 @@ Une excellente source de documentation sont les forums de discussion qui sont un lieu où des programmeurs échangent questions et réponses. Un message d'erreur entré sur un moteur de recherche Internet permet souvent de tomber sur des échanges de ce type, sur des problèmes résolus par d'autres. -Le plus connu est `stackoverflow/tkinter `_. +Le plus connu est `stackoverflow/tkinter +`_. + +Sous Linux, l'utilisation de ce module requiert une étape supplémentaire +si l'erreur suivante se produit : +`ImportError: No module named 'Tkinter' +`_. + +:: + + sudo apt-get install python3-tk .. _chap_interface_intro_section: @@ -105,7 +116,7 @@ Les exemples de codes des paragraphes qui suivent permettent de disposer les obj dans une fenêtre qui ne s'affichera pas sans les quelques lignes de code supplémentaires présentées au paragraphe :ref:`mainloop_fenetre_principale` et l'utilisation d'une méthode -`pack `_ +:epkg:`tkinter.Widget.pack` L'exemple suivant crée un objet : :: @@ -179,7 +190,7 @@ Bouton .. index:: bouton Un bouton a pour but de faire le lien entre une fonction et un clic de souris. -Un bouton correspond à la classe `Button `_ +Un bouton correspond à la classe :epkg:`tkinter.Button` Pour créer un bouton, il suffit d'écrire la ligne suivante : :: @@ -188,7 +199,7 @@ Pour créer un bouton, il suffit d'écrire la ligne suivante : Il est possible que le texte de ce bouton doive changer après quelques temps. Dans ce cas, il faut appeler la méthode -`config `_ comme suit : +:epkg:`tkinter.Button.config` comme suit : :: @@ -254,7 +265,7 @@ Zone de saisie Une zone de saisie a pour but de recevoir une information entrée par l'utilisateur. Une zone de saisie correspond à la classe -`Entry `_ ; +:epkg:`tkinter.Entry` ; pour en créer une, il suffit d'écrire la ligne suivante : :: @@ -262,7 +273,7 @@ pour en créer une, il suffit d'écrire la ligne suivante : saisie = tkinter.Entry () Pour modifier le contenu de la zone de saisie, il faut utiliser -la méthode `insert `_ +la méthode :epkg:`tkinter.Entry.insert` qui insère un texte à une position donnée. :: @@ -272,14 +283,14 @@ qui insère un texte à une position donnée. saisie.insert (pos, "contenu") Pour obtenir le contenu de la zone de saisie, il faut utiliser la méthode -`get `_ : +:epkg:`tkinter.Entry.get` : :: contenu = saisie.get () Pour supprimer le contenu de la zone de saisie, il faut utiliser la -méthode `delete `_. +méthode :epkg:`tkinter.Entry.delete`. Cette méthode supprime le texte entre deux positions. :: @@ -306,7 +317,7 @@ on peut utiliser l'instruction suivante : La seconde zone de saisie est grisée par rapport à la première. Les zones de saisie grisées ne peuvent pas être modifiées. Pour obtenir cet état, il suffit d'utiliser la méthode -`config `_ +:epkg:`tkinter.Entry.config` comme pour les précédents objets. Cette option sera rappelée au paragraphe :ref:`methode_communes_interface`. @@ -319,7 +330,7 @@ Zone de saisie à plusieurs lignes Une zone de saisie à plusieurs lignes est identique à la précédente à ceci près qu'elle autorise la saisie d'un texte sur plusieurs lignes. Cette zone -correspond à la classe `Text `_. +correspond à la classe :epkg:`tkinter.Text`. Pour créer une telle zone, il suffit d'écrire la ligne suivante : :: @@ -327,7 +338,7 @@ Pour créer une telle zone, il suffit d'écrire la ligne suivante : saisie = tkinter.Text () Pour modifier le contenu de la zone de saisie, il faut utiliser la méthode -`insert `_ +:epkg:`tkinter.Text.insert` qui insère un texte à une position donnée. La méthode diffère de celle de la classe :ref:`Entry ` puisque la position d'insertion est maintenant une chaîne de caractères contenant deux nombres séparés @@ -341,7 +352,7 @@ par un point : le premier nombre désigne la ligne, le second la position sur ce saisie.insert (pos, "première ligne\nseconde ligne") Pour obtenir le contenu de la zone de saisie, il faut utiliser la méthode -`get `_ +:epkg:`tkinter.Text.get` qui retourne le texte entre deux positions. La position de fin n'est pas connue, on utilise la chaîne de caractères ``"end"`` pour désigner la fin de la zone de saisie. @@ -353,7 +364,7 @@ connue, on utilise la chaîne de caractères ``"end"`` pour désigner la fin de contenu = saisie.get (pos1, pos2) Pour supprimer le contenu de la zone de saisie, il faut utiliser la méthode -`delete `_. +:epkg:`tkinter.Text.delete`. Cette méthode supprime le texte entre deux positions. :: @@ -388,7 +399,7 @@ on utilise l'instruction suivante : L'image précédente montre une zone de saisie à plusieurs lignes. Pour griser cette zone, il suffit d'utiliser la méthode -`config `_ +:epkg:`tkinter.Text.config` rappelée au paragraphe :ref:`methode_communes_interface`. .. _tkinter-checkbutton: @@ -399,7 +410,7 @@ Case à cocher .. index:: CheckButton, case à cocher Une case à cocher correspond à la classe -`Checkbutton `_. +:epkg:`tkinter.CheckButton`. Pour créer une case à cocher, il suffit d'écrire la ligne suivante : :: @@ -410,9 +421,9 @@ Pour créer une case à cocher, il suffit d'écrire la ligne suivante : case = tkinter.Checkbutton (variable = v) En fait, ce sont deux objets qui sont créés. Le premier, de type -`IntVar `_, +:epkg:`tkinter.IntVar`, mémorise la valeur de la case à cocher. Le second objet, de type -`Checkbutton `_, gère l'apparence +:epkg:`tkinter.CheckButton`, gère l'apparence au niveau de l'interface graphique. La raison de ces deux objets est plus évidente dans le cas de l'objet :ref:`RadioButton ` décrit au paragraphe suivant. @@ -446,7 +457,7 @@ Il est possible d'associer du texte à l'objet case à cocher : La troisième est grisée par rapport à la première. Les cases grisées ne peuvent pas être cochées. Pour obtenir cet état, il suffit d'utiliser la méthode -`config `_ +:epkg:`tkinter.CheckButton.config` rappelée au paragraphe :ref:`methode_communes_interface`. .. _tkinter-radiobutton: @@ -457,7 +468,7 @@ Case ronde ou bouton radio .. index:: RadioButton, bouton radio, IntVar Une case ronde ou *bouton radio* correspond à la classe -`Radiobutton `_. +:epkg:`tkinter.RadioButton`. Elles fonctionnent de manière semblable à des cases à cocher excepté le fait qu'elles n'apparaissent jamais seules : elles fonctionnent en groupe. Pour créer un groupe de trois cases rondes, il suffit d'écrire la ligne suivante : @@ -520,7 +531,7 @@ Liste Un objet liste contient une liste d'intitulés qu'il est possible de sélectionner. Une liste correspond à la classe -`ListBox `_. +:epkg:`tkinter.ListBox`. Pour la créer, il suffit d'écrire la ligne suivante : :: @@ -538,7 +549,7 @@ on utilise l'instruction suivante : li.config (width = 10, height = 5) On peut insérer un élément dans la liste avec la méthode -`insert `_ : +:epkg:`tkinter.ListBox.insert` : :: @@ -546,7 +557,7 @@ On peut insérer un élément dans la liste avec la méthode li.insert (pos, "première ligne") On peut supprimer des intitulés de cette liste avec la méthode -`delete `_. +:epkg:`tkinter.ListBox.delete`. :: @@ -557,8 +568,7 @@ On peut supprimer des intitulés de cette liste avec la méthode Les intitulés de cette liste peuvent ou non être sélectionnés. Cliquer sur un intitulé le sélectionne mais la méthode -`select_set `_ -permet aussi de le faire. +:epkg:`tkinter.ListBox.select_set` permet aussi de le faire. :: @@ -568,8 +578,7 @@ permet aussi de le faire. # pos2 inclus ou seulement celui d'indice pos1 si pos2 == None Réciproquement, il est possible d'enlever un intitulé de la sélection à -l'aide de la méthode -`select_clear `_. +l'aide de la méthode :epkg:`tkinter.ListBox.select_clear`. :: @@ -578,16 +587,14 @@ l'aide de la méthode # retire la sélection de tous les éléments entre les indices # pos1 et pos2 inclus ou seulement celui d'indice pos1 si pos2 == None -La méthode -`curselection `_ +La méthode :epkg:`tkinter.ListBox.curselection` permet d'obtenir la liste des indices des éléments sélectionnés. :: sel = li.curselection () -La méthode -`get `_ +La méthode :epkg:`tkinter.ListBox.get` permet récupérer un élément de la liste tandis que la méthode \codes{size} retourne le nombre d'éléments :\indextkk{size}\indextkk{get} :: @@ -605,11 +612,11 @@ Exemple de liste. La seconde liste est grisée et ne peut être modifiée. - .. image:: images/list2.png Pour obtenir l'état grisé, il faut appeler la méthode -`config `_ +:epkg:`tkinter.ListBox.config` et rappelée au paragraphe :ref:`methode_communes_interface`. Il est possible d'adjoindre une barre de défilement verticale. Il faut pour cela inclure l'objet dans une sous-fenêtre -`Frame `_ +:epkg:`tkinter.Frame` qui est définie au paragraphe :ref:`interf_fraph_sous_gene` comme dans l'exemple suivant : @@ -617,7 +624,7 @@ comme dans l'exemple suivant : frame = tkinter.Frame (parent) scrollbar = tkinter.Scrollbar (frame) - li = tkinter.Listbox (frame, width = 88, height = 6, \ + li = tkinter.Listbox (frame, width = 88, height = 6, yscrollcommand = scrollbar.set) scrollbar.config (command = li.yview) li.pack (side = tkinter.LEFT) @@ -625,19 +632,16 @@ comme dans l'exemple suivant : Il suffit de transposer cet exemple pour ajouter une barre de défilement horizontale. Toutefois, il est préférable d'utiliser un objet prédéfini présent dans le module -`tix `_ -qui est une extension du module -`tkinter `_. +:mod:`tkinter.tix` qui est une extension du module :epkg:`tkinter`. Elle est présentée au paragraphe :ref:`chap_interface_exemple_programme`. -Lorsqu'on insère plusieurs objets -`ListBox `_ +Lorsqu'on insère plusieurs objets :epkg:`tkinter.ListBox` dans une seule fenêtre, ces objets partagent par défaut la même sélection. Autrement dit, lorsqu'on clique sur un élément de la seconde -`ListBox `_, +:epkg:`tkinter.ListBox`, l'élément sélectionné dans la première ne l'est plus. Afin de pouvoir sélectionner un élément dans chaque -`ListBox `_, il faut ajouter +:epkg:`tkinter.ListBox`, il faut ajouter dans les paramètres du constructeur l'option ``exportselection=0`` comme l'illustre l'exemple suivant : @@ -647,7 +651,7 @@ comme l'illustre l'exemple suivant : Il existe des méthodes plus avancées qui permettent de modifier l'aspect graphique d'un élément comme la méthode -`itemconfig `_. +:epkg:`tkinter.ListBox.itemconfig`. Son utilisation est peu fréquente à moins de vouloir réaliser une belle interface graphique. Le paragraphe :ref:`more_than_on_e_window_ref_liste` montre l'utilisation qu'on peut en faire. @@ -658,11 +662,8 @@ Liste avec barre de défilement, Combobox ---------------------------------------- C'est une liste avec une barre de défilement incluse qui est présente dans l'extension -`ttk `_ -qui étend la liste des objets proposés par -`tkinter `_. -C'est ce que fait l'objet -`ttk.Combobox `_. +:mod:`tkinter.ttk` qui étend la liste des objets proposés par +:epkg:`tkinter`. C'est ce que fait l'objet :epkg:`tkinter.ttk.Combobox`. :: @@ -683,8 +684,7 @@ C'est ce que fait l'objet root.mainloop() # idem -Les extensions `ttk `_ -et `tix `_ +Les extensions :mod:`tkinter.ttk` et :mod:`tkinter.tix` ne sont pas très bien documentés mais il existe de nombreuses réponses sur les forums de discussions. @@ -699,8 +699,7 @@ Canevas ------- Pour dessiner, il faut utiliser un objet canevas, -correspondant à la classe -`Canvas `_. +correspondant à la classe :epkg:`tkinter.Canvas`. Pour la créer, il suffit d'écrire la ligne suivante : :: @@ -719,22 +718,25 @@ on utilise l'instruction suivante : Cet objet permet de dessiner des lignes, des courbes, d'écrire du texte grâce aux méthodes -`create_line `_, -`create_rectangle `_, -`create_text `_. +:epkg:`tkinter.Canvas.create_line`, +:epkg:`tkinter.Canvas.create_rectangle`, +:epkg:`tkinter.Canvas.create_text`. :: - # dessine deux lignes du point 10,10 au point 40,100 et au point 200,60 - # de couleur bleue, d'épaisseur 2 + # dessine deux lignes du point 10,10 au point 40,100 et au point 200,60 + # de couleur bleue, d'épaisseur 2 ca.create_line (10,10,40,100, 200,60, fill = "blue", width = 2) - # dessine une courbe du point 10,10 au point 200,60 - # de couleur rouge, d'épaisseur 2, c'est une courbe de Bézier - # pour laquelle le point 40,100 sert d'assise + + # dessine une courbe du point 10,10 au point 200,60 + # de couleur rouge, d'épaisseur 2, c'est une courbe de Bézier + # pour laquelle le point 40,100 sert d'assise ca.create_line (10,10, 40,100, 200,60, smooth=1, fill = "red", width = 2) - # dessine un rectangle plein de couleur jaune, de bord noir et d'épaisseur 2 + + # dessine un rectangle plein de couleur jaune, de bord noir et d'épaisseur 2 ca.create_rectangle (300,100,60,120, fill = "gray", width = 2) - # écrit du texte de couleur noire au point 80,80 et avec la police arial + + # écrit du texte de couleur noire au point 80,80 et avec la police arial ca.create_text (80,80, text = "écrire", fill = "black", font = "arial") Visuellement, cela donne : @@ -754,8 +756,7 @@ Méthodes communes ----------------- Nous avons vu que tous les objets présentés dans ce -paragraphe possèdent une méthode -``config`` +paragraphe possèdent une méthode ``config`` qui permet de définir l'état du widget (grisé ou normal) voire de la faire disparaître (voir paragraphe :ref:`disposition_paragraphe_python`). @@ -828,9 +829,9 @@ Emplacements Chacun des objets (ou widgets) présentés au paragraphe précédent possède trois méthodes qui permettent de déterminer sa position dans une fenêtre : -`pack `_, -`grid `_, -`place `_. +:epkg:`tkinter.Widget.pack`, +:epkg:`tkinter.Widget.grid`, +:epkg:`tkinter.Widget.place`. Les deux premières permettent de disposer les objets sans se soucier ni de leur dimension ni de leur position. La fenêtre gère cela automatiquement. La dernière place les objets dans une fenêtre à @@ -889,8 +890,8 @@ Il n'est pas toujours évident d'obtenir du premier coup le positionnement des objets souhaités au départ et il faut tâtonner pour y arriver. Lorsque un objet n'est plus nécessaire, il est possible de le faire disparaître en appelant la méthode -`pack_forget `_. -Le rappel de la méthode `pack `_ +:epkg:`tkinter.Widget.pack_forget`. +Le rappel de la méthode :epkg:`tkinter.Widget.pack` le fera réapparaître mais rarement au même endroit. :: @@ -901,7 +902,7 @@ le fera réapparaître mais rarement au même endroit. Méthode grid ++++++++++++ -La méthode `grid `_ +La méthode :epkg:`tkinter.Widget.grid` suppose que la fenêtre qui les contient est organisée selon une grille dont chaque case peut recevoir un objet. L'exemple suivant place trois objets dans les cases de coordonnées @@ -922,7 +923,7 @@ compte des lignes et colonnes vides. .. image:: images/grid1.png -La méthode `grid `_ +La méthode :epkg:`tkinter.Widget.grid` possède plusieurs options, en voici cinq : * ``column`` : colonne dans laquelle sera placée l'objet. @@ -938,8 +939,8 @@ possède plusieurs options, en voici cinq : d'étendre l'objet d'un bord à l'autre en écrivant ``sticky="N+S"`` ou ``sticky="E+W"``. -Enfin, comme pour la méthode `pack `_, -il existe une méthode `grid_forget `_ +Enfin, comme pour la méthode :epkg:`tkinter.Widget.pack`, +il existe une méthode :epkg:`tkinter.Widget.grid_forget` qui permet de faire disparaître les objets. :: @@ -949,25 +950,25 @@ qui permet de faire disparaître les objets. Méthode place +++++++++++++ -La méthode `place `_ +La méthode :epkg:`tkinter.Widget.place` est sans doute la plus simple à comprendre puisqu'elle permet de placer chaque objet à une position définie par des coordonnées. Elle peut être utilisée en parallèle avec les méthodes -`place `_ et -`grid `_. +:epkg:`tkinter.Widget.place` et +:epkg:`tkinter.Widget.grid`. :: l = tkinter.Label(text="première ligne") l.place (x=10, y=50) -La méthode `place_forget `_ +La méthode :epkg:`tkinter.Widget.place_forget` permet de faire disparaître un objet placer avec cette méthode. L'inconvénient de cette méthode survient lorsqu'on cherche à modifier l'emplacement d'un objet : il faut en général revoir les positions de tous les autres éléments de la fenêtre. On procède souvent par tâtonnement pour construire une fenêtre et disposer les objets. Ce travail est beaucoup -plus long avec la méthode `place `_. +plus long avec la méthode :epkg:`tkinter.Widget.place`. .. _interf_fraph_sous_gene: @@ -981,7 +982,7 @@ C'est aussi la seule façon de réutiliser un groupe de contrôle ou widgets dans plusieurs fenêtres sans avoir à dupliquer le code. La figure suivante montre deux objets regroupés dans un rectangle avec à sa gauche une zone de texte. Les boîtes sont des instances de la classe -`Frame `_. +:epkg:`tkinter.Frame`. .. image:: images/frame.png @@ -989,7 +990,7 @@ Les deux premiers objets, une zone de texte au-dessus d'une zone de saisie, sont regroupés dans une boîte rectangle rouge, invisible à l'écran. A droite et centrée, une dernière zone de texte. Cet alignement est plus simple à réaliser en regroupant les deux premiers objets dans un object -`Frame `_. +:epkg:`tkinter.Frame`. Pour créer une boîte, il suffit d'écrire la ligne suivante : :: @@ -1021,7 +1022,7 @@ la fenêtre de la figure ci-dessus. e.pack (side = tkinter.RIGHT) # positionne e à l'intérieur # de la fenêtre principale -L'utilisation de ces blocs `Frame `_ +L'utilisation de ces blocs :epkg:`tkinter.Frame` est pratique lorsque le même ensemble de contrôles apparaît dans plusieurs fenêtres différentes ou au sein de la même fenêtre. Cette possibilité est envisagée au paragraphe @@ -1069,12 +1070,12 @@ Une fenêtre peut contenir plusieurs zones de saisie, toutes capables d'intercepter la pression d'une touche du clavier et d'ajouter la lettre correspondante à la zone de saisie. Or la seule qui ajoute effectivement une lettre à son contenu est celle qui a le -`focus `_. +:epkg:`tkinter.Widget.focus`. La pression de la touche tabulation fait passer le focus d'un objet à l'autre. La figure ci-dessous montre un bouton qui a le focus. Lorsqu'on désire qu'un objet en particulier ait le focus, il suffit d'appeler la méthode -`focus_set `_. +:epkg:`tkinter.Widget.focus_set`. .. image:: images/focus.png @@ -1160,7 +1161,7 @@ fonctions à des événements liés à leur apparence. Toutefois, pour un jeu par exemple, il est parfois nécessaire d'avoir accès au mouvement de la souris et il faut revenir aux événements *bruts*. Un événement est décrit par la classe -`Event `_ +:epkg:`tkinter.Event` dont les attributs listés par la table suivante décrivent l'événement qui sera la plupart du temps la pression d'une touche du clavier ou le mouvement de la souris. @@ -1196,10 +1197,10 @@ La liste complète est accessible avec l'instruction suivante : import tkinter help(tkinter.Event) -La méthode `bind `_ +La méthode :epkg:`tkinter.Widget.bind` permet d'exécuter une fonction lorsqu'un certain événement donné est intercepté par un objet donné. La fonction exécutée accepte un seul -paramètre de type `Event `_ +paramètre de type :epkg:`tkinter.Event` qui est l'événement qui l'a déclenchée. Cette méthode a pour syntaxe : :: @@ -1210,7 +1211,7 @@ qui est l'événement qui l'a déclenchée. Cette méthode a pour syntaxe : caractères ``ev`` dont les valeurs possibles sont décrites ci-dessous. ``fonction`` est la fonction qui est appelée lorsque l'événement survient. Cette fonction ne prend qu'un paramètre de type -`Event `_. +:epkg:`tkinter.Event`. .. list-table:: :widths: 5 10 @@ -1247,7 +1248,7 @@ La liste complète est accessible avec l'instruction suivante : help(tkinter.Label.bind) L'exemple suivant utilise la méthode -`bind `_ +:epkg:`tkinter.Widget.bind` pour que le seul bouton de la fenêtre intercepte toute pression d'une touche, tout mouvement et toute pression du premier bouton de la souris lorsque le curseur est au dessus de la zone graphique du bouton. @@ -1333,9 +1334,9 @@ suivantes qui signifie que l'événement ```` n'existe pas. Il arrive parfois qu'un événement ne doive pas être associé à un seul objet mais à tous ceux que la fenêtre contient. C'est -l'objectif de la méthode `bind_all `_. +l'objectif de la méthode :epkg:`tkinter.Widget.bind_all`. Sa syntaxe est exactement la même que la méthode -`bind `_. +:epkg:`tkinter.Widget.bind`. :: @@ -1347,9 +1348,9 @@ On utilise peu cette fonction, on préfère construire des objets propres De la même manière qu'il est possible d'associer un événement à un objet d'une fenêtre, il est possible d'effectuer l'opération inverse qui consiste à supprimer cette association. -La méthode `unbind `_ +La méthode :epkg:`tkinter.Widget.unbind` désactive un événement associé à un objet. -La méthode `unbind_all `_ +La méthode :epkg:`tkinter.Widget.unbind_all` désactive un événement associé pour tous les objets d'une fenêtre. :: @@ -1379,7 +1380,7 @@ Menu Les menus fonctionnent de la même manière que les boutons. Chaque intitulé du menu est relié à une fonction qui sera exécutée à la condition que l'utilisateur sélectionne cet -intitulé. L'objet `Menu `_ +intitulé. L'objet :epkg:`tkinter.Menu` ne désigne pas le menu dans son ensemble mais seulement un niveau. Par exemple, le menu présenté par la figure suivante est en fait un assemblage de trois menus auquel on pourrait ajouter d'autres sous-menus. @@ -1389,7 +1390,7 @@ assemblage de trois menus auquel on pourrait ajouter d'autres sous-menus. La représentation d'un menu tient plus d'un graphe que d'une liste. Chaque intitulé du menu peut être connecté à une fonction ou être le point d'entrée d'un nouveau sous-menu. Pour créer un menu ou un sous-menu, il suffit de créer un objet de type -`Menu `_ : +:epkg:`tkinter.Menu` : :: @@ -1404,10 +1405,10 @@ le suivant : root.config (menu = m) ``root`` est ici la fenêtre principale mais ce pourrait être également -une fenêtre de type `Toplevel `_ +une fenêtre de type :epkg:`tkinter.Toplevel` Ce menu peut aussi être le sous-menu associé à un intitulé d'un menu existant. La méthode -`add_cascade `_ +:epkg:`tkinter.Menu.add_cascade` permet d'ajouter un sous-menu associé à un label : :: @@ -1417,7 +1418,7 @@ permet d'ajouter un sous-menu associé à un label : mainmenu.add_cascade (label = "sous-menu 1", menu = msousmenu) En revanche, si on souhaite affecter une fonction à un menu, on utilisera -la méthode `add_command `_ +la méthode :epkg:`tkinter.Menu.add_command`. :: @@ -1473,7 +1474,7 @@ Ce qui donne : Chaque intitulé d'un menu est ajouté en fin de liste, il est possible d'en supprimer certains à partir de leur position avec -la méthode `delete `_. +la méthode :epkg:`tkinter.Menu.delete`. :: @@ -1502,32 +1503,32 @@ un seul bouton qui, s'il est pressé, mettra fin à l'application. La table suivante regroupe les fonctions les plus utilisées. Celles-ci s'applique à une fenêtre de type -`Toplevel `_ +:epkg:`tkinter.Toplevel` qui est aussi le type de la fenêtre principale. .. list-table:: :widths: 5 10 :header-rows: 0 - * - `destroy() `_ + * - :epkg:`tkinter.Toplevel.destroy` - Détruit la fenêtre. - * - `deiconify() `_ + * - :epkg:`tkinter.Toplevel.deiconify` - La fenêtre reprend une taille normale. - * - `geometry(s) `_ + * - :epkg:`tkinter.Toplevel.geometry` (s) - Modifie la taille de la fenêtre. ``s`` est une chaîne de - caractères de type ``"wxh±x±y"``. + caractères de type ``"w x h ± x ± y"``. ``w`` et ``h`` sont la largeur et la hauteur. ``x`` et ``y`` sont la position du coin supérieur haut à l'écran. - * - `iconify() `_ + * - :epkg:`tkinter.Toplevel.iconify` - La fenêtre se réduit à un icône. - * - `resizable(w,h) `_ + * - :epkg:`tkinter.Toplevel.resizable` (w, h) - Spécifie si la fenêtre peut changer de taille. ``w`` et ``h`` sont des booléens. - * - `title(s) `_ + * - :epkg:`tkinter.Toplevel.title` (s) - Change le titre de la fenêtre, ``s`` est une chaîne de caractères. - * - `withdraw() `_ + * - :epkg:`tkinter.Toplevel.withdraw` - Fait disparaître la fenêtre. La fonction inverse est - `deiconify() `_. + :epkg:`tkinter.Toplevel.deiconify`. D'autres fenêtres et contrôles ------------------------------ @@ -1535,20 +1536,18 @@ D'autres fenêtres et contrôles *tkinter* ne propose pas beaucoup de *widgets*, pas autant que la liste étendue qu'on trouve dans la plupart des applications. Deux extensions complètent cette liste -`ttk `_ -et `tix `_. +:mod:`tkinter.ttk` et :mod:`tkinter.tix`. On trouve notamment : -* `Combobox `_ -* `Notebook `_ -* `Progressbar `_ -* `Treeview `_ +* :epkg:`tkinter.ttk.Combobox` +* :epkg:`tkinter.ttk.Notebook` +* :epkg:`tkinter.ttk.Progressbar` +* :epkg:`tkinter.ttk.Treeview` -`tix `_ propose -des widgets un peu plus complexes : +:mod:`tkinter.tix` propose des widgets un peu plus complexes : -* `DirTree `_ -* `FileSelectBox `_ +* :epkg:`tkinter.tix.DirTree` +* :epkg:`tkinter.tix.FileSelectBox` Cette liste n'est pas exhaustive. @@ -1557,7 +1556,7 @@ Créer une seconde boîte de dialogues Lorsqu'un programme doit utiliser plusieurs fenêtres et non pas une seule, l'emploi de l'objet -`Toplevel `_ +:epkg:`tkinter.Toplevel` est inévitable. L'instruction ``root = tkinter.Tk()`` crée la fenêtre principale, l'instruction ``win = tkinter.Toplevel()`` crée une seconde fenêtre qui fonctionne exactement comme la fenêtre @@ -1573,16 +1572,16 @@ messages via la méthode ``mainloop``. Un cas d'utilisation simple est par exemple un bouton pressé qui fait apparaître une fenêtre permettant de sélectionner un fichier, cette seconde fenêtre sera un objet -`Toplevel `_. +:epkg:`tkinter.Toplevel`. Il n'est pas nécessaire de s'étendre plus sur cet objet, son comportement est identique à celui de la fenêtre principale, les fonctions décrites au paragraphe :ref:`fonction_predefeinies_toot` s'appliquent également -aux objets `Toplevel `_. +aux objets :epkg:`tkinter.Toplevel`. Il reste néanmoins à préciser un dernier point. Tous les objets précédemment décrits au paragraphe :ref:`interface_graphique_objet_s` doivent inclure un paramètre supplémentaire dans leur constructeur pour signifier qu'ils appartiennent à un objet -`Toplevel `_ +:epkg:`tkinter.Toplevel` et non à la fenêtre principale. Par exemple, pour créer une zone de texte, la syntaxe est la suivante : @@ -1591,7 +1590,7 @@ une zone de texte, la syntaxe est la suivante : # zone_texte appartient à la fenêtre principale zone_texte = tkinter.Label (text = "premier texte") -Pour l'inclure à une fenêtre `Toplevel `_, +Pour l'inclure à une fenêtre :epkg:`tkinter.Toplevel`, cette syntaxe devient : :: @@ -1602,20 +1601,20 @@ cette syntaxe devient : Lors de la définition de chaque objet ou *widget*, si le premier paramètre est de type -`Toplevel `_, +:epkg:`tkinter.Toplevel`, alors ce paramètre sera affecté à la fenêtre passée en premier argument et non à la fenêtre principale. Ce principe est le même que celui de la sous-fenêtre -`Frame `_ +:epkg:`tkinter.Frame` (voir paragraphe :ref:`interf_fraph_sous_gene`). La seule différence provient du fait que l'objet -`Toplevel `_ +:epkg:`tkinter.Toplevel` est une fenêtre autonome qui peut attendre un message grâce à la méthode ``mainloop``, ce n'est pas le cas de l'objet -`Frame `_. +:epkg:`tkinter.Frame`. Toutefois, il est possible d'afficher plusieurs fenêtres -`Toplevel `_ simultanément. +:epkg:`tkinter.Toplevel` simultanément. Le programme suivant en est un exemple : :: @@ -1646,15 +1645,15 @@ Le programme suivant en est un exemple : Fenêtres standard ----------------- -Le module `tix `_ +Le module :mod:`tkinter.tix` propose une fenêtre de sélection de fichiers identique à celle de la figure suivante. -`tkinter `_ +:epkg:`tkinter` a l'avantage d'être simple et ne nécessite pas un long apprentissage pour le maîtriser mais il est limité. Pour ce type de fenêtres qu'on retrouve dans la plupart des programmes, il existe presque toujours des solutions toutes faites, via le module -`tix `_ +:mod:`tkinter.tix` par exemple. On trouve également de nombreux programmes sur Internet par le biais de moteurs de recherche. Le programme ci-dessous affiche une fenêtre qui permet de sélectionner un fichier. @@ -1670,20 +1669,19 @@ affiche une fenêtre qui permet de sélectionner un fichier. import os class FileSelection(object) : - """classe permettant de sélectionner un fichier - ou un répertoire à travers une boîte de dialogue""" - - def __init__(self, parent, titre = "Sélection de fichier", \ - chemin = None, file = True, exist= True) : - """ - initialise la classe - - @param parent parent - @param titre titre de la fenêtre - @param chemin fichier ou répertoire par défaut - @param file True : fichier, False : répertoire - @param exist True : le répertoire ou le fichier - sélectionné doit exister""" + """ + Classe permettant de sélectionner un fichier + ou un répertoire à travers une boîte de dialogue. + + :param parent: parent + :param titre: titre de la fenêtre + :param chemin: fichier ou répertoire par défaut + :param file: True, fichier, False, répertoire + :param exist: True, le répertoire ou le fichier sélectionné doit exister + """ + + def __init__(self, parent, titre="Sélection de fichier", + chemin=None, file=True, exist=True) : self.parent = parent self.titre = titre self.chemin = chemin @@ -1836,7 +1834,7 @@ affiche une fenêtre qui permet de sélectionner un fichier. print("fichier sélectionné ", win.chemin) Il faut comparer ce programme à celui qu'on écrirait avec -l'extension `tix `_ : +l'extension :mod:`tkinter.tix` : :: @@ -1891,7 +1889,7 @@ Compte à rebours Il est possible de demander à un objet d'appeler une fonction après un certains laps de temps exprimé un millisecondes. Le programme suivant crée un objet de type -`Label `_. +:epkg:`tkinter.Label`. Il contient une fonction qui change son contenu et lui affecte un compte à rebours qui impose à l'objet de rappeler cette fonction 1000 millisecondes plus tard. Le résultat est un programme qui crée @@ -1922,10 +1920,10 @@ L'intitulé de l'objet ``Label`` change toutes les secondes. .. image:: images/after.png -La méthode `after `_ +La méthode `tkinter.Label.after` retourne un entier permettant d'identifier le compte à rebours qu'il est possible d'interrompre en utilisant la méthode -`after_cancel `_. +:epkg:`tkinter.Label.after_cancel` Dans l'exemple précédent, il faudrait utiliser l'instruction suivante : @@ -1942,14 +1940,14 @@ On peut personnifier un contrôle. Par exemple, on peut mettre en évidence l'intitulé d'une liste sous le curseur de la souris. Le moyen le plus simple est de créer une nouvelle classe qui se substituera au classique -`ListBox `_. +:epkg:`tkinter.ListBox`. Il suffit que cette nouvelle classe hérite de -`ListBox `_ +:epkg:`tkinter.ListBox` en prenant soin de lui donner un constructeur reprenant les mêmes paramètres que celui de la classe -`ListBox `_. +:epkg:`tkinter.ListBox`. De cette façon, il suffit de remplacer -`ListBox `_ +:epkg:`tkinter.ListBox` par ``MaListbox`` pour changer l'apparence d'une liste. :: @@ -1986,7 +1984,9 @@ Dans ce cas précis, on fait en sorte que le contrôle intercepte le mouvement du curseur. Lorsque celui-ci bouge, la méthode ``mouvement`` est appelée comme le constructeur de ``MaListbox`` l'a spécifié. La méthode ``nearest`` permet de définir l'intitulé le plus proche du curseur. -La méthode ``itemconfig`` permet de changer le fond de cet intitulé en gris après avoir modifié le fond de l'intitulé précédent pour qu'il retrouve sa couleur d'avant. Le résultat est illustré la figure~\ref{listbox_curseur_soiut}. +La méthode ``itemconfig`` permet de changer le fond de cet intitulé en gris après avoir modifié le +fond de l'intitulé précédent pour qu'il retrouve sa couleur d'avant. +Le résultat est illustré la figure suivante. .. image:: images/listboxs.png @@ -2044,8 +2044,8 @@ Ce programme crée trois boutons et attache à chacun d'entre eux une méthode de la classe ``MaFenetre``. Le constructeur de la classe prend comme unique paramètre un pointeur sur un objet qui peut être la fenêtre principale, un objet de type -`Frame `_ ou -`Toplevel `_. +:epkg:`tkinter.Frame` ou +:epkg:`tkinter.Toplevel`. Cette construction permet de considérer cet ensemble de trois boutons comme un objet à part entière ; de ce fait il peut être inséré plusieurs fois comme le montre l'exemple suivant illustré par la figure qui suit. @@ -2079,7 +2079,7 @@ première fonction pour revenir à la fonction ``mainloop``, la seule capable de saisir le prochain événement. La figure qui suit précise la gestion des messages. -`tkinter `_ +:epkg:`tkinter` se charge de la réception des messages puis de l'appel au traitement correspondant indiqué par la méthode ou la fonction attachée à l'événement. Le programmeur peut définir les traitements associés @@ -2156,7 +2156,7 @@ d'événements particulière. Communiquer un résultat par message ----------------------------------- -Le module `tkinter `_ +Le module :epkg:`tkinter` permet de définir ses propres messages qui peuvent servir à communiquer des informations. Une fonction est par exemple appelée lorsqu'un bouton est pressé. Celle-ci, une fois terminée, retourne son résultat sous forme @@ -2167,7 +2167,7 @@ Le programme suivant utilise ce concept. La pression d'un bouton appelle une fonction ``event_generate`` qui génère un message personnalisé ``<>`` avec comme paramètre ``rooty=-5``. A son tour, celui-ci est attrapé et dirigé vers la fonction ``perso`` qui affiche l'attribut -``y_root`` de la classe `Event `_ +``y_root`` de la classe :epkg:`tkinter.Event` qui a reçu la valeur \codes{-5} lors de l'appel de la fonction ``event_generate``. Ce procédé ne permet toutefois que de renvoyer que quelques résultats entiers. diff --git a/_doc/sphinxdoc/source/c_lang/collections.rst b/_doc/c_lang/collections.rst similarity index 96% rename from _doc/sphinxdoc/source/c_lang/collections.rst rename to _doc/c_lang/collections.rst index 3bf6c3cb..27f3d844 100644 --- a/_doc/sphinxdoc/source/c_lang/collections.rst +++ b/_doc/c_lang/collections.rst @@ -89,7 +89,7 @@ le rend plus lisible. Counter ======= -:class:`collection.Counter` est un dictionnaire spécifique dans les valeurs +:class:`collections.Counter` est un dictionnaire spécifique dans les valeurs sont entières. Il est très pratique pour compter les éléments. L'exemple :ref:`comptage ` s'écrit en une ligne. @@ -105,7 +105,7 @@ L'exemple :ref:`comptage ` s'écrit en une ligne. deque ===== -:class:`collection.deque` est une liste qui supporte l'insertion +:class:`collections.deque` est une liste qui supporte l'insertion d'éléments en bout de liste et au début également (`liste chaînée `_). diff --git a/_doc/sphinxdoc/source/c_lang/constructions.rst b/_doc/c_lang/constructions.rst similarity index 92% rename from _doc/sphinxdoc/source/c_lang/constructions.rst rename to _doc/c_lang/constructions.rst index 5253411b..ae42fd93 100644 --- a/_doc/sphinxdoc/source/c_lang/constructions.rst +++ b/_doc/c_lang/constructions.rst @@ -8,7 +8,7 @@ Constructions classiques .. contents:: :local: -Constructions classiques +Constructions fréquentes ======================== .. exreflist:: diff --git a/_doc/sphinxdoc/source/c_lang/dates.rst b/_doc/c_lang/dates.rst similarity index 72% rename from _doc/sphinxdoc/source/c_lang/dates.rst rename to _doc/c_lang/dates.rst index 86c0a35a..e61efd66 100644 --- a/_doc/sphinxdoc/source/c_lang/dates.rst +++ b/_doc/c_lang/dates.rst @@ -12,8 +12,7 @@ Dates datetime ======== -Le module `datetime `_ -fournit une classe `datetime `_ +Le module :mod:`datetime` fournit une classe :class:`datetime.datetime` qui permet de faire des opérations et des comparaisons sur les dates et les heures. L'exemple suivant calcule l'âge d'une personne née le 11 août 1975. @@ -27,16 +26,14 @@ L'exemple suivant calcule l'âge d'une personne née le 11 août 1975. age = jour - naissance # calcule une différence print(age) # affiche 12614 days, 1:25:10.712000 -L'objet `datetime `_ +L'objet :class:`datetime.datetime` autorise les soustractions et les comparaisons entre deux dates. Une soustraction -retourne un objet de type -`timedelta `_ +retourne un objet de type :class:`datetime.timedelta` qui correspond à une durée qu'on peut multiplier par un réel ou ajouter à un -objet de même type ou à un objet de type -`datetime `_. +objet de même type ou à un objet de type :class:`datetime.datetime`. L'utilisation de ce type d'objet évite de se pencher sur tous les problèmes de conversion. -Le module `calendar `_ +Le module :mod:`calendar` est assez pratique pour construire des calendriers. Le programme ci-dessous affiche une liste de t-uples incluant le jour et le jour de la semaine du mois d'août 1975. Dans cette liste, on y trouve le t-uple ``(11,0)`` @@ -65,8 +62,7 @@ dépend du système d'exploitation. C'est un nombre réel : la partie entière est un nombre de seconde, la partie décimale donne les millisecondes. La valeur n'a pas de sens exploitable à moins de la convertir en un format compréhensible. -C'est ce que fait la fonction -`fromtimestamp `_. +C'est ce que fait la fonction :meth:`datetime.datetime.fromtimestamp`. .. runpython:: :showcode: diff --git a/_doc/sphinxdoc/source/c_lang/encoding.rst b/_doc/c_lang/encoding.rst similarity index 100% rename from _doc/sphinxdoc/source/c_lang/encoding.rst rename to _doc/c_lang/encoding.rst diff --git a/_doc/sphinxdoc/source/c_lang/images/rawinput.png b/_doc/c_lang/images/rawinput.png similarity index 100% rename from _doc/sphinxdoc/source/c_lang/images/rawinput.png rename to _doc/c_lang/images/rawinput.png diff --git a/_doc/sphinxdoc/source/c_lang/index.rst b/_doc/c_lang/index.rst similarity index 95% rename from _doc/sphinxdoc/source/c_lang/index.rst rename to _doc/c_lang/index.rst index 28db3912..240bf84c 100644 --- a/_doc/sphinxdoc/source/c_lang/index.rst +++ b/_doc/c_lang/index.rst @@ -12,4 +12,3 @@ Variables et fonctions collections dates encoding - faq diff --git a/_doc/sphinxdoc/source/c_lang/syntaxe.rst b/_doc/c_lang/syntaxe.rst similarity index 98% rename from _doc/sphinxdoc/source/c_lang/syntaxe.rst rename to _doc/c_lang/syntaxe.rst index bc966e6f..ec1b937d 100644 --- a/_doc/sphinxdoc/source/c_lang/syntaxe.rst +++ b/_doc/c_lang/syntaxe.rst @@ -138,7 +138,7 @@ Définition et syntaxe .. mathdef:: :title: test :tag: Définition - :lid: test_test + :label: test_test Les tests permettent d'exécuter des instructions différentes selon la valeur d'une condition logique. @@ -195,7 +195,7 @@ il est possible de condenser l'écriture avec le mot-clé ``elif`` : Le décalage des instructions par rapport aux lignes contenant les mots-clés ``if``, ``elif``, ``else`` est très important : il fait partie de la syntaxe du langage -et s'appelle l'`indentation `_. +et s'appelle l':epkg:`indentation`. Celle-ci permet de grouper les instructions ensemble. Le programme suivant est syntaxiquement correct même si le résultat n'est pas celui désiré. @@ -297,18 +297,18 @@ qui sont eux-mêmes sur les opérateurs logiques ``not``, ``and``, ``or``. Il est tout de même conseillé d'ajouter des parenthèses en cas de doute. C'est ce qu décrit la page `Operator precedence `_. -Ecriture condensée ------------------- +Ecriture condensée (test) +------------------------- Il existe deux écritures condensées de tests. La première consiste à écrire un test et l'unique instruction qui en dépend sur une seule ligne. :: -if condition : - instruction1 -else : - instruction2 + if condition : + instruction1 + else : + instruction2 Ce code peut tenir en deux lignes : @@ -327,8 +327,8 @@ variable à tester est entière. ``if x == 1 or x == 6 or x == 50 :`` peut être résumé simplement par ``if x in (1,6,50) :`` ou ``if x in {1,6,50}:`` pour les grandes listes. -Exemple -------- +Exemple (test) +-------------- L'exemple suivant associe à la variable ``signe`` le signe de la variable ``x``. @@ -356,7 +356,7 @@ Son écriture condensée lorsqu'il n'y a qu'une instruction à exécuter : print(signe) Le programme suivant saisit une ligne au clavier et dit si c'est "oui" ou "non" qui a été saisi. -La fonction `input `_ retourne +La fonction :func:`input` retourne ce qui vient de l'utilisateur : :: @@ -367,7 +367,7 @@ ce qui vient de l'utilisateur : else: print "non" -La fonction `input `_ +La fonction :func:`input` invite l'utilisateur d'un programme à saisir une réponse lors de l'exécution du programme. Tant que la touche entrée n'a pas été pressée, l'exécution du programme ne peut continuer. Cette fonction est en réalité peu utilisée. Les interfaces graphiques sont @@ -617,8 +617,7 @@ qui réduit l'exemple suivant en trois lignes: La boucle la plus répandue est celle qui parcourt des indices entiers compris entre *0* et *n-1*. On utilise pour cela la boucle ``for`` et la fonction -`range `_ -comme dans l'exemple qui suit. +:epkg:`range` comme dans l'exemple qui suit. .. runpython:: :showcode: @@ -780,8 +779,8 @@ Il est alors possible de parcourir plusieurs séquences print(y), " est le carré de ", x # affichage à droite -Ecriture condensée ------------------- +Ecriture condensée (for) +------------------------ Comme pour les tests, lorsque les boucles ne contiennent qu'une seule instruction, il est possible de l'écrire sur @@ -1054,7 +1053,7 @@ elles ont un identificateur et une valeur qui est dans ce cas un morceau de code. Cette précision explique certaines syntaxes du chapitre :ref:`chap_interface` sur les interfaces graphiques ou celle introduite en fin de chapitre au -paragraphe :ref:`paragraphe_fonction_variable`. +paragraphe :ref:`fonction comme paramètre `. .. _par_fonction_syntaxe: @@ -1130,8 +1129,8 @@ Sans l'instruction ``return``, toute fonction retourne ``None``. .. _para_fonction_exemple: -Exemple -------- +Exemple (for) +------------- Le programme suivant utilise deux fonctions. La première convertit des coordonnées cartésiennes en @@ -1152,8 +1151,7 @@ les résultats de la première pour tout couple de valeurs def affichage (x,y): r, t = coordonnees_polaires(x, y) - print("cartésien (%f,%f) --> polaire (%f,%f degrés)" \ - % (x,y,r,math.degrees(t))) + print("cartésien (%f,%f) --> polaire (%f,%f degrés)" % (x,y,r,math.degrees(t))) affichage(1,1) affichage(0.5,1) @@ -1186,7 +1184,6 @@ est spécifiée pour un paramètre, alors tous ceux qui suivent devront eux aussi avoir une valeur par défaut. Exemple : -% .. runpython:: :showcode: @@ -1740,8 +1737,8 @@ L'appel à cette fonction suit quant à lui la syntaxe suivante : :: - fonction (valeur_1, ..., valeur_n, \ - liste_valeur_1, ..., liste_valeur_p, \ + fonction (valeur_1, ..., valeur_n, + liste_valeur_1, ..., liste_valeur_p, nom_1 = v_1, ..., nom_q = v_q) Où ``fonction`` est un nom de fonction, ``valeur_1`` à @@ -1910,7 +1907,7 @@ l'ensemble des entiers compris entre 0 et *n* exclu # fonction fonction_yield, elle simule la liste # [0,1,2] -Le programme affiche tous les entiers compris entre~0 et 4 inclus ainsi que le +Le programme affiche tous les entiers compris entre 0 et 4 inclus ainsi que le texte ``"yield 1"`` ou ``"yield 2"`` selon l'instruction ``yield`` qui a retourné le résultat. Lorsque la fonction a finalement terminé son exécution, le prochain appel agit comme si c'était la première @@ -2021,6 +2018,8 @@ un exemple d'utilisation de la fonction ``compile`` avec la fonction ``eval``. .. _par_indentation: +.. _fonction_sorted_enumerate: + Indentation =========== @@ -2064,8 +2063,7 @@ sont présentées :ref:`plus bas `. .. index:: map -La fonction `map `_ -permet d'écrire des boucles de façon simplifiée. +La fonction :func:`map` permet d'écrire des boucles de façon simplifiée. Elle est utile dans le cas où on souhaite appliquer la même fonction à tous les éléments d'un ensemble. Par exemple les deux dernières lignes du programme suivant sont équivalentes. @@ -2081,11 +2079,11 @@ lignes du programme suivant sont équivalentes. print(map(est_pair, l)) print(list(map(est_pair, l))) # affiche [0, 1, 0, 0, 1, 0] -La fonction `map `_ +La fonction :func:`map` retourne un itérateur et non un ensemble. Cela explique le second résultat du programme précédent. Pour obtenir les résultats, il faut explicitement parcourir l'ensemble des résultats. C'est ce que fait la dernière instruction. La fonction -`map `_ +:func:`map` est une :ref:`fonction générateur `. Elle peut aider à simplifier l'écriture lorsque plusieurs listes sont impliquées. Ici encore, les deux dernières lignes sont équivalentes. @@ -2116,8 +2114,6 @@ pour obtenir l'équivalent de la fonction .. index:: sorted -.. _fonction_sorted_enumerate: - Comme pour les dictionnaires, la fonction `sorted `_ permet de parcourir les éléments d'une liste de façon ordonnée. @@ -2139,9 +2135,8 @@ la liste ``li`` demeure inchangée alors qu'elle est triée dans le premier prog .. index:: enumerate -La fonction `enumerate `_ -permet d'éviter l'emploi de la fonction -`range `_ +La fonction :func:`enumerate` +permet d'éviter l'emploi de la fonction :epkg:`range` lorsqu'on souhaite parcourir une liste alors que l'indice et l'élément sont nécessaires. .. runpython:: diff --git a/_doc/sphinxdoc/source/c_lang/types.rst b/_doc/c_lang/types.rst similarity index 95% rename from _doc/sphinxdoc/source/c_lang/types.rst rename to _doc/c_lang/types.rst index 85af8113..2ec2e25f 100644 --- a/_doc/sphinxdoc/source/c_lang/types.rst +++ b/_doc/c_lang/types.rst @@ -10,7 +10,7 @@ Types et variables du langage python Variables ========= -.. index:: variabl +.. index:: variable Il est impossible d'écrire un programme sans utiliser de variable. Ce terme désigne le fait d'attribuer un nom ou identificateur à des informations : @@ -96,9 +96,9 @@ du programme mais n'en faisant pas partie comme dans l'exemple qui suit. .. index:: backslash, \ -Le *python* impose une instruction par ligne. Il n'est pas possible d'utiliser -deux lignes pour écrire une affectation à moins de conclure chaque ligne qui -n'est pas la dernière par le symbole ``\`` +Le *python* privilégie une instruction par ligne mais il n'est pas possible d'utiliser +plusieurs lorsqu'il n'y a aucune ambiguïté. +Dans le cas contraire, le symbole ``\`` permet d'indiquer que la ligne n'est pas finie. L'exemple suivant est impossible. :: @@ -113,6 +113,13 @@ Il devrait être rédigé comme suit : x = \ 5.5 +Mais les parenthèses sont à privilégier : + +:: + + x = ( + 5.5) + Avec ce symbole, les longues instructions peuvent être écrites sur plusieurs lignes de manière plus lisibles, de sorte qu'elles apparaissent en entier à l'écran. Si le dernier caractère est une virgule, il est implicite. @@ -395,7 +402,7 @@ Ces deux opérateurs seront utilisés ultérieurement, (paragraphe :ref:`boucle_for`), ``is`` lors de l'étude des listes (paragraphe :ref:`par_liste_copie` et des :ref:`classes `). Bien souvent, les booléens sont utilisés de manière implicite lors -de tests (paragraphe :ref:`test_test`) ce qui n'empêche pas de les +de tests (paragraphe :ref:`test `) ce qui n'empêche pas de les déclarer explicitement. :: @@ -424,8 +431,7 @@ Création d'une chaîne de caractères - str Ce texte est compris entre deux guillemets ou deux apostrophes, ces deux symboles sont interchangeables. -Le type *python* est `str `_. -L'exemple suivant montre comment +Le type *python* est :class:`str`. L'exemple suivant montre comment créer une chaîne de caractères. Il ne faut pas confondre la partie entre guillemets ou apostrophes, qui est une constante, de la variable qui la contient. @@ -459,15 +465,13 @@ lorsque le texte contient plusieurs lignes, il suffit de les encadrer entre deux symboles ``"""`` ou ``'''`` pour que l'interpréteur *python* considère l'ensemble comme une chaîne de caractères et non comme une série d'instructions. -.. _extra_caractere: - Par défaut, le *python* ne permet pas l'insertion de caractères tels que les accents dans les chaînes de caractères, le paragraphe :ref:`par_intro_accent_code` explique comment résoudre ce problème. De même, pour insérer un guillemet dans une chaîne de caractères encadrée elle-même par des guillemets, il faut le faire précéder du symbole ``\``. La séquence ``\`` est appelée un extra-caractère -(voir table :ref:`extra_caractere`) ou un caractère d'échappement. +(voir table suivante) ou un caractère d'échappement. .. index:: \n, \\, \%, \t, \r, extra caractère @@ -492,7 +496,8 @@ du symbole ``\``. La séquence ``\`` est appelée un extra-caractère d'un système *Windows* à *Linux* car *Windows* l'ajoute automatiquement à tous ses fichiers textes * - ... - - Lire `String and Bytes literals `_. + - Lire `String and Bytes literals + `_. Liste des extra-caractères les plus couramment utilisés à l'intérieur d'une chaîne de caractères @@ -577,9 +582,7 @@ Où ``s`` est une chaîne de caractères, ``fonction`` est le nom de l'opération que l'on veut appliquer à ``s``, ``res`` est le résultat de cette manipulation. -.. _string_method: - -La table :ref:`string_method` présente une liste non exhaustive +La table suivante présente une liste non exhaustive des fonctions disponibles dont un exemple d'utilisation suit. Cette syntaxe ``variable.fonction(arguments)`` est celle des classes. @@ -667,7 +670,7 @@ Formatage d'une chaîne de caractères Syntaxe % ^^^^^^^^^ -*python* (`printf-style String Formatting `_) +*python* (:epkg:`printf-style String Formatting`) offre une manière plus concise de former une chaîne de caractères à l'aide de plusieurs types d'informations en évitant la conversion explicite de ces informations (type ``str``) @@ -680,7 +683,7 @@ de décimales fixe. Le format est le suivant : ".... %c1 .... %c2 " % (v1,v2) ``c1`` est un code choisi parmi ceux de la table -:ref:`format_print`. Il indique le format dans lequel la variable +:ref:`format print `. Il indique le format dans lequel la variable ``v1`` devra être transcrite. Il en est de même pour le code ``c2`` associé à la variable ``v2``. Les codes insérés dans la chaîne de caractères seront remplacés par les variables citées entre @@ -696,8 +699,8 @@ Voici concrètement l'utilisation de cette syntaxe : x = 5.5 d = 7 s = "caractères" - res = "un nombre réel %f et un entier %d, une chaîne de %s, \n" \ - "un réel d'abord converti en chaîne de caractères %s" % (x,d,s, str(x+4)) + res = ("un nombre réel %f et un entier %d, une chaîne de %s, \n" + "un réel d'abord converti en chaîne de caractères %s" % (x,d,s, str(x+4))) print(res) res = "un nombre réel " + str (x) + " et un entier " + str (d) + \ ", une chaîne de " + s + \ @@ -729,7 +732,7 @@ Exemple : .. _format_string: -Il existe d'autres formats regroupés dans la table :ref:`format_print`. +Il existe d'autres formats regroupés dans la table suivante. L'aide reste encore le meilleur réflexe car le langage *python* est susceptible d'évoluer et d'ajouter de nouveaux formats. @@ -748,7 +751,7 @@ est susceptible d'évoluer et d'ajouter de nouveaux formats. * - ``s`` - chaîne de caractères * - ... - - Lire `printf-style String Formatting `_. + - Lire :epkg:`printf-style String Formatting`. Méthode format ^^^^^^^^^^^^^^ @@ -807,8 +810,8 @@ Dates : d = datetime.datetime.now() print('{:%Y-%m-%d %H:%M:%S}'.format(d)) -Le site :epkg:`pyformat` recense d'autres usages de la méthode -:epkg:`format` comme l'affichage de chaînes de caractères tronquées. +Le site :epkg:`format` recense d'autres usages de la méthode +`format` comme l'affichage de chaînes de caractères tronquées. .. runpython:: :showcode: @@ -984,7 +987,8 @@ que ceux présentés au paragraphe :ref:`type_nombre` et décrivant les nombres. c = complex(1,1) print(c*c) -Le langage *python* offre la possibilité de créer ses propres types immuables (voir :ref:`classe_slots_att`) +Le langage *python* offre la possibilité de créer ses propres types immuables +(voir :ref:`__slots__ `) mais ils seront définis à partir des types immuables présentés jusqu'ici. .. _l-type-bytes: @@ -994,10 +998,9 @@ bytes .. index:: bytes -Le type `bytes `_ +Le type :class:`bytes` représente un tableau d'octets. Il fonctionne quasiment pareil que le type -`str `_. -Les opérations qu'on peut faire dessus sont quasiment identiques : +:class:`str`. Les opérations qu'on peut faire dessus sont quasiment identiques : .. index:: count, find, replace, split, join, startswith, endswith @@ -1052,7 +1055,7 @@ par **b** : .. index:: encode, decode Le type *bytes* est très utilisé quand il s'agit de convertit une chaîne -de caractères d'un `encoding `_ +de caractères d'un :epkg:`encoding` à l'autre. .. runpython:: @@ -1063,7 +1066,7 @@ de caractères d'un `encoding `_ +Les :epkg:`encoding` sont utiles dès qu'une chaîne de caractères contient un caractère non anglais (accent, sigle...). Les bytes sont aussi très utilisés pour `sérialiser `_ un objet. @@ -1104,16 +1107,15 @@ bytearray .. index:: bytearray -Le type `bytearray `_ -est la version *mutable* du type :ref:`l-type-bytes`. +Le type :epkg:`bytearray` est la version *mutable* du type :ref:`l-type-bytes`. Liste +++++ .. index:: liste, list -Définition et fonctions -^^^^^^^^^^^^^^^^^^^^^^^ +Définition et méthodes (list) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. mathdef:: :tag: Définition @@ -1229,8 +1231,8 @@ qui s'appliquent sur les chaînes de caractères, elles sont présentées par la Si ``reverse`` est ``True``, alors le tri est décroissant. Lire `Sorting HOW TO `_. -Exemples -^^^^^^^^ +Exemples (list) +^^^^^^^^^^^^^^^ L'exemple suivant montre une utilisation de la méthode ``sort``. @@ -1300,8 +1302,7 @@ Fonction range .. index:: range Les listes sont souvent utilisées dans des boucles ou notamment -par l'intermédiaire de la fonction -`range `_. +par l'intermédiaire de la fonction :epkg:`range`. Cette fonction retourne un `itérateur `_ sur des entiers. Nous verrons les itérateurs plus tard. Disons pour le moment les itérateurs ont l'apparence d'un ensembe mais ce n'en est pas un. @@ -1366,7 +1367,7 @@ L'instruction ``for el in x :`` se traduit littéralement par : Il existe également des notations abrégées lorsqu'on cherche à construire une liste à partir d'une autre. Le programme suivant construit la liste des -entiers de 1 à 5 à partir du résultat retourné par la fonction ``range``. +entiers de 1 à 5 à partir du résultat retourné par la fonction :epkg:`range`. .. runpython:: :showcode: @@ -1392,7 +1393,7 @@ Cette définition de liste peut également inclure des tests ou des boucles imbr y = [ i for i in range(0,5) if i % 2 == 0] # sélection les éléments pairs print(y) # affiche [0,2,4] - z = [ i+j for i in range(0,5) \ + z = [ i+j for i in range(0,5) for j in range(0,5)] # construit tous les nombres i+j possibles print(z) @@ -1429,7 +1430,7 @@ bouts par petits bouts comme le montre le premier exemple ci-dessous. Cette construction peut s'avérer très lente lorsque le résultat est long. Dans ce cas, il est nettement plus rapide d'ajouter chaque morceau dans une liste puis de les concaténer en une seule fois grâce à la méthode -`join `_ +:meth:`str.join`. :: @@ -1444,6 +1445,8 @@ dans une liste puis de les concaténer en une seule fois grâce à la méthode .. _par_liste_copie: +.. _copy_deepopy_remarque: + Copie +++++ @@ -1484,8 +1487,7 @@ n'est pas recopiée, la liste reçoit seulement un nom de variable. L'affectation est en fait l'association d'un nom avec un objet (voir paragraphe :ref:`par_copie_objet`). Pour copier une liste, il faut utiliser la fonction -`copy `_ -du module `copy `_ +:func:`copy.copy` du module :mod:`copy`. .. runpython:: :showcode: @@ -1499,7 +1501,7 @@ du module `copy `_ print(l) # affiche [4,5,6] print(l2) # affiche [4, 'modif', 6] -Le module `copy `_ +Le module :mod:`copy` est une extension interne. Cette syntaxe sera vue au chapitre :ref:`chap_module`. Ce point sera rappelé au paragraphe :ref:`classe_list_dict_ref_par`. L'opérateur ``==`` permet de savoir si deux listes sont égales même si l'une est @@ -1521,14 +1523,10 @@ ou si l'une est une copie de l'autre comme le montre l'exemple suivant : **Fonction ``copy`` et ``deepcopy``** -.. _copy_deepopy_remarque_: - -Le comportement de la fonction -`copy `_ +Le comportement de la fonction :func:`copy.copy` peut surprendre dans le cas où une liste contient d'autres listes. Pour être sûr que chaque élément d'une liste a été correctement recopiée, -il faut utiliser la fonction -`deepcopy `_. +il faut utiliser la fonction :epkg:`deepcopy`. La fonction est plus longue mais elle recopie toutes les listes que ce soit une liste incluse dans une liste elle-même incluse dans une autre liste elle-même incluse... @@ -1548,7 +1546,7 @@ dans une autre liste elle-même incluse... print(l [0] is l2 [0]) # affiche True print(l [0] is l3 [0]) # affiche False -La fonction `deepcopy `_ +La fonction :epkg:`deepcopy` est plus lente à exécuter car elle prend en compte les références récursives comme celles de l'exemple suivant où deux listes se contiennent l'une l'autre. @@ -1588,8 +1586,8 @@ ce nom ou parcourir toute la liste si jamais celui-ci ne s'y trouve pas. Dans le cas d'un dictionnaire, cette recherche du nom sera beaucoup plus rapide à écrire et à exécuter. -Définition et fonctions -^^^^^^^^^^^^^^^^^^^^^^^ +Définition et méthodes (dict) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. index:: clé, valeur @@ -1686,8 +1684,8 @@ Les itérateurs sont des objets qui permettent de parcourir rapidement un dictio ils seront décrits en détail au chapitre :ref:`chap_classe` sur les classes. Un exemple de leur utilisation est présenté dans le paragraphe suivant. -Exemples -^^^^^^^^ +Exemples (dict) +^^^^^^^^^^^^^^^ Il n'est pas possible de trier un dictionnaire. L'exemple suivant permet néanmoins d'afficher tous les éléments d'un dictionnaire selon @@ -1697,7 +1695,7 @@ les boucles (voir chapitre :ref:`chap_boucle`). .. runpython:: :showcode: - d = { "un":1, "zéro":0, "deux":2, "trois":3, "quatre":4, "cinq":5, \ + d = { "un":1, "zéro":0, "deux":2, "trois":3, "quatre":4, "cinq":5, "six":6, "sept":1, "huit":8, "neuf":9, "dix":10 } key = list(d.keys()) key.sort() @@ -1711,7 +1709,7 @@ seront les clés et réciproquement. .. runpython:: :showcode: - d = { "un":1, "zero":0, "deux":2, "trois":3, "quatre":4, "cinq":5, \ + d = { "un":1, "zero":0, "deux":2, "trois":3, "quatre":4, "cinq":5, "six":6, "sept":1, "huit":8, "neuf":9, "dix":10 } dinv = { } # création d'un dictionnaire vide, on parcout @@ -1729,7 +1727,7 @@ sans créer de liste intermédiaire. Ceci explique ce qu'affiche le programme su .. runpython:: :showcode: - d = { "un":1, "zero":0, "deux":2, "trois":3, "quatre":4, "cinq":5, \ + d = { "un":1, "zero":0, "deux":2, "trois":3, "quatre":4, "cinq":5, "six":6, "sept":1, "huit":8, "neuf":9, "dix":10 } print(d.items()) print(list(d.items())) @@ -1751,8 +1749,8 @@ Dans le meilleur des cas, l'erreur suivante survient : .. _par_dictionnaire_copie: -Copie -^^^^^ +Copie (dict) +^^^^^^^^^^^^ .. index:: copy, copie @@ -1775,7 +1773,7 @@ Lorsqu'on affecte un dictionnaire à une variable, celui-ci n'est pas recopié, le dictionnaire reçoit seulement un nom de variable. L'affectation est en fait l'association d'un nom avec un objet (voir paragraphe :ref:`par_copie_objet`). Pour copier un dictionnaire, on peut utiliser la méthode -`copy `_. +:meth:`dict.copy`. .. runpython:: :showcode: @@ -1792,7 +1790,7 @@ Le mot-clé ``is`` a la même signification pour les dictionnaires que pour les listes, l'exemple du paragraphe :ref:`par_liste_copie` est aussi valable pour les dictionnaires. Il en est de même pour la remarque concernant la fonction -`deepcopy `_. +:epkg:`deepcopy`. Cette fonction recopie les listes et les dictionnaires. .. _cle_dict_modificalbe_apr: @@ -1931,11 +1929,6 @@ comme l'intersection, l'union. servir comme clé dans un dictionnaire ou comme valeur dans un `set` ou `frozenset`. -.. todoext:: - :title: Compléter le paragraphe sur les set - - set, frozen set - Matrices et DataFrames ====================== @@ -1974,7 +1967,7 @@ La fonction `str `_ qui effectue cette conversion. Dans ce cas, le résultat peut être -interprété par la fonction `eval `_ +interprété par la fonction :epkg:`eval` qui se charge de la conversion inverse. Pour les types simples comme ceux présentés dans ce chapitre, ces deux fonctions retournent des résultats identiques. @@ -1995,7 +1988,7 @@ Fonction ``eval`` .. index:: eval Comme le suggère le paragraphe précédent, la fonction -`eval `_ +:epkg:`eval` permet d'évaluer une chaîne de caractères ou plutôt de l'interpréter comme si c'était une instruction en *python*. Le petit exemple suivant permet de tester toutes les opérations de @@ -2013,18 +2006,16 @@ calcul possibles entre deux entiers. Le programme va créer une chaîne de caractères pour chacune des opérations et celle-ci sera évaluée grâce à la fonction -`eval `_ +:epkg:`eval` comme si c'était une expression numérique. Il faut bien sûr que les variables que l'expression mentionne existent durant son évaluation. Informations fournies par *python* ++++++++++++++++++++++++++++++++++ -.. index:: dir - Bien que les fonctions ne soient définies que plus tard (paragraphe :ref:`par_fonction`, il peut être intéressant de mentionner -la fonction `dir `_ +la fonction :epkg:`dir` qui retourne la liste de toutes les variables créées et accessibles à cet instant du programme. L'exemple suivant : @@ -2048,7 +2039,7 @@ l'environnement dans lequel est exécuté le programme *python* : - Ce module contient tous les éléments présents dès le début d'un programme *python*, il contient entre autres les types présentés dans ce - chapitre et des fonctions simples comme ``range``. + chapitre et des fonctions simples comme :epkg:`range`. * - ``__doc__`` - C'est une chaîne commentant le fichier, c'est une chaîne de caractères insérée aux premières lignes @@ -2059,7 +2050,7 @@ l'environnement dans lequel est exécuté le programme *python* : * - ``__name__`` - Contient le nom du module. -La fonction `dir `_ +La fonction :epkg:`dir` est également pratique pour afficher toutes les fonctions d'un module. L'instruction ``dir(sys)`` affiche la liste des fonctions du module `sys `_ diff --git a/_doc/sphinxdoc/source/c_module/arbo.png b/_doc/c_module/arbo.png similarity index 100% rename from _doc/sphinxdoc/source/c_module/arbo.png rename to _doc/c_module/arbo.png diff --git a/_doc/sphinxdoc/source/c_module/files.rst b/_doc/c_module/files.rst similarity index 93% rename from _doc/sphinxdoc/source/c_module/files.rst rename to _doc/c_module/files.rst index f48d7bc0..f49239a7 100644 --- a/_doc/sphinxdoc/source/c_module/files.rst +++ b/_doc/c_module/files.rst @@ -37,7 +37,7 @@ commençant par 06... En utilisant des modules tels que ou encore `openpyxl `_, il serait possible d'étendre cette fonctionnalité aux fichiers de type `pdf `_ -et aux fichiers `Excel `_. +et aux fichiers :epkg:`Excel`. Format texte ============ @@ -46,11 +46,10 @@ Format texte Les `fichiers texte `_ sont les plus simples : ce sont des suites de caractères. Le format -`HTML `_ et -`XML `_ font partie de +:epkg:`HTML` et :epkg:`XML` font partie de cette catégorie. Ils servent autant à conserver des informations qu'à en échanger comme par exemple transmettre une matrice à -`Excel `_. +:epkg:`Excel`. Ce format, même s'il est simple, implique une certaine organisation dans la façon de conserver les données afin de pouvoir les récupérer. Le cas le @@ -152,11 +151,10 @@ Ou encore : f.write ( str (mat [i][j]) + "\t") f.write ("\n") -La fonction `open `_ -accepte deux paramètres, le premier est le nom du fichier, -le second définit le mode d'ouverture : ``"w"`` pour écrire (**w**rite), -"a" pour écrire et ajouter (**a**ppend), -"r" pour lire (**r**ead). Ceci signifie que la fonction ``open`` +La fonction :func:`open` accepte deux paramètres, le premier est le nom du fichier, +le second définit le mode d'ouverture : ``"w"`` pour écrire (**w** rite), +"a" pour écrire et ajouter (**a** ppend), +"r" pour lire (**r** ead). Ceci signifie que la fonction ``open`` sert à ouvrir un fichier quelque soit l'utilisation qu'on en fait. A la première écriture dans un fichier (premier appel à la fonction ``write``, @@ -286,13 +284,11 @@ d'une ligne. C'est pour cela que la lecture est parfois suivie d'une l_net = [ s.strip ("\n\r") for s in l ] Les informations peuvent être structurées de façon plus élaborée dans un fichier texte, -c'est le cas des formats `HTML `_ et -`XML `_. +c'est le cas des formats :epkg:`HTML` et +:epkg:`XML`. Pour ce type de format plus complexe, il est déconseillé de concevoir soi-même un programme capable de les lire, il existe presque toujours un module qui permette -de le faire. C'est le cas du module -`html.parser `_ -ou `xml `_. +de le faire. C'est le cas du module :mod:`html.parser` ou :mod:`xml`. De plus, les modules sont régulièrement mis à jour et suivent l'évolution des formats qu'ils décryptent. @@ -346,7 +342,7 @@ Encoding et les accents Par défaut, un fichier n'accepte pas d'enregistrer des accents, uniquement les acaractères `ascii `_. C'est pourquoi il faut presque tout le temps utiliser le paramètre *encoding* -de la fonction `open `_ +de la fonction :func:`open` que ce soit pour écrire ou lire. :: @@ -372,8 +368,8 @@ sur les fichiers textes existent comme `7-zip `_. Ce format n'est pas seulement utilisé pour compresser mais aussi comme un moyen de regrouper plusieurs fichiers en un seul. -Lecture -------- +Lecture (zip) +------------- L'exemple suivant permet par exemple d'obtenir la liste des fichiers inclus dans un fichier *zip* : @@ -399,16 +395,16 @@ lu est au format texte donc lisible). On retrouve dans ce cas les étapes d'ouverture et de fermeture même si la première est implicitement inclus dans le constructeur de la classe -`ZipFile `_. +:class:`zipfile.ZipFile`. -Ecriture --------- +Ecriture (zip) +-------------- Pour créer un fichier *zip*, le procédé ressemble à la création de n'importe quel fichier. La seule différence provient du fait qu'il est possible de stocker le fichier à compresser sous un autre nom à l'intérieur du fichier *zip*, ce qui explique les deux premiers arguments -de la méthode `write `_. +de la méthode :meth:`zipfile.ZipFile.write`. Le troisième paramètre indique si le fichier doit être compressé `ZIP_DEFLATED `_ ou non `ZIP_STORED `_. @@ -457,7 +453,7 @@ proche de celui d'un spammeur. content = f.read() part.set_payload(content) encoders.encode_base64(part) - part.add_header('Content-Disposition', \ + part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file)) msg.attach(part) @@ -666,8 +662,8 @@ qui peut être alors pris en compte grâce aux expressions régulières if i > 5: break -Format binaire -============== +Sans format ou format binaire +============================= .. index:: format binaire @@ -689,20 +685,20 @@ l'ordinateur : une suite d'octets (bytes en anglais). Deux étapes vont intervenir que ce soit pour l'écriture : 1. On récupère les informations dans une suite d'octets - (fonction `pack `_ - du module `struct `_). + (fonction :func:`struct.pack` + du module :mod:`struct`). 2. On les écrit dans un fichier - (méthode `write `_ + (méthode :meth:`io.RawIOBase.write` affiliée aux fichiers). Ou la lecture : 1. On lit une suite d'octets depuis un fichier - (méthode `read `_ + (méthode :meth:`io.RawIOBase.read` affiliée aux fichiers). 2. On transforme cette suite d'octets pour retrouver l'information qu'elle formait initialement - (fonction `unpack `_). + (fonction :func:`struct.unpack`). L'utilisation de fichiers binaires est moins évidente qu'il n'y paraît et il faut faire appel à des modules spécialisés alors que la gestion des @@ -721,8 +717,7 @@ problèmes que pour un fichier texte : il faut organiser les données avant de les enregistrer pour savoir comment les retrouver. Les types immuables (réel, entier, caractère) sont assez simples à gérer dans ce format. Pour les objets complexes, *python* propose une solution grâce au module -`pickle `_ -(voir aussi le modile `dill `_ +:mod:`pickle` (voir aussi le modile :epkg:`dill` pour des types telles que des fonctions). Ecriture dans un fichier binaire @@ -734,11 +729,11 @@ C'est le code ``"wb"`` qui est important (*w* pour *write*, *b* pour *binary*), il spécifie le mode d'ouverture ``"w"`` et le format ``"b"``. La fermeture est la même que pour un fichier texte. -Le module `struct `_ -et la fonction `pack `_ +Le module :mod:`struct` +et la fonction :func:`struct.pack` permet de convertir les informations sous forme de chaîne de caractères avant de les enregistrer au format binaire. -La fonction `pack `_ +La fonction :func:`struct.pack` construit une chaîne de caractères égale au contenu de la mémoire. Son affichage avec la fonction *print* produit quelque chose d'illisible le plus souvent. @@ -759,7 +754,7 @@ Lecture d'un fichier binaire Le code associé à l'ouverture d'un fichier binaire en mode lecture est ``"rb"``, cela donne : ``open("", "rb")``. La lecture utilise la fonction -`unpack `_ +:func:`struct.unpack` pour effectuer la conversion inverse, celle d'une chaîne de caractères en entiers, réels, ... Le paragraphe suivant illustre la lecture et l'écriture au format binaire. @@ -797,7 +792,7 @@ fichier à l'aide d'un éditeur de texte. print(x) print(s) -Les résultats de la méthode `unpack `_ +Les résultats de la méthode :func:`struct.unpack` apparaissent dans un tuple mais les données sont correctement récupérées. Ce programme fait aussi apparaître une des particularité du format binaire. On suppose ici que la chaîne de caractères est toujours de @@ -860,7 +855,7 @@ Objets plus complexes .. index:: sérialisation Il existe un moyen de sauvegarder dans un fichier des objets -plus complexes à l'aide du module `pickle `_ +plus complexes à l'aide du module :mod:`pickle` Celui-ci permet de stocker dans un fichier le contenu d'un dictionnaire à partir du moment où celui-ci contient des objets standard du langage *python*. Le principe pour l'écriture est le suivant : @@ -884,7 +879,7 @@ La lecture est aussi simple : dico = pickle.load(fb) lis = pickle.load(fb) -Un des avantages du module `pickle `_ +Un des avantages du module :mod:`pickle` est de pouvoir gérer les références circulaires : il est capable d'enregistrer et de relire une liste qui se contient elle-même, ce peut être également une liste qui en contient une autre qui contient la première... @@ -963,8 +958,8 @@ que le montre l'exemple suivant : print(t) -Le module `pickle `_ +Le module :mod:`pickle` ne permet de sérialiser tout type d'objet comme les fonctions. Il est parfois utile de sauver une fonction car c'est un paramètre du programme. Il faut dans ce cas soit le faire soi-même, soit utiliser le module -`dill `_. +:epkg:`dill`. diff --git a/_doc/sphinxdoc/source/c_module/index.rst b/_doc/c_module/index.rst similarity index 94% rename from _doc/sphinxdoc/source/c_module/index.rst rename to _doc/c_module/index.rst index d4673a73..1a3d2f25 100644 --- a/_doc/sphinxdoc/source/c_module/index.rst +++ b/_doc/c_module/index.rst @@ -9,4 +9,3 @@ Entrées, Sorties, Modules files serialization module - faq diff --git a/_doc/sphinxdoc/source/c_module/module.rst b/_doc/c_module/module.rst similarity index 94% rename from _doc/sphinxdoc/source/c_module/module.rst rename to _doc/c_module/module.rst index 4712334b..eaf74565 100644 --- a/_doc/sphinxdoc/source/c_module/module.rst +++ b/_doc/c_module/module.rst @@ -3,9 +3,9 @@ .. _chap_module: -======= -Modules -======= +=================== +Module ou extension +=================== .. contents:: :local: @@ -19,8 +19,8 @@ fichier principal, il contient son point d'entrée, les premières instructions exécutées. Les autres fichiers sont considérés comme des modules, en quelque sorte, des annexes qui contiennent tout ce dont le fichier principal a besoin. -Modules -======= +Un module +========= Exemple ------- @@ -28,7 +28,7 @@ Exemple .. index:: point d'entrée Cet exemple montre comment répartir un programme sur deux fichiers. -Le premier est appelé \textit{module} car il n'inclut pas le point d'entrée du programme. +Le premier est appelé *module* car il n'inclut pas le point d'entrée du programme. .. mathdef:: :title: point d'entrée du programme @@ -132,7 +132,7 @@ La dernière instruction affiche l'aide du module : FILE module_exemple.py -Pour importer un module, il suffit d'insérer l'instruction \ +Pour importer un module, il suffit d'insérer l'instruction ``import nom_module`` avant d'utiliser une des choses qu'il définit. Ces importations sont souvent regroupées au début du programme, elles sont de cette façon mises en évidence même s'il est possible de les @@ -174,8 +174,7 @@ Le module ``module_exemple`` contient une variable ``exemple_variable`` peut être modifiée au cours de l'exécution du programme. Il est possible de revenir à sa valeur initiale en forçant *python* à recharger le module grâce à la fonction `import.reload `_ -elle même implémentée dans le module -`importlib `_. +elle même implémentée dans le module :mod:`importlib`. .. mathdef:: :title: importer un module (1) @@ -286,7 +285,7 @@ d'installation de *python*. Si ce n'est pas le cas, il faut préciser sys.path.append("répertoire où se trouve le module à importer") import nom_module -La variable `sys.path `_ +La variable :epkg:`sys.path` contient les répertoires où *python* va chercher les modules. Le premier d'entre eux est le répertoire du programme. Il suffit d'ajouter à cette liste le répertoire désiré. @@ -397,8 +396,7 @@ module si celui-ci est désigné par un nom de fichier incluant son répertoire. Il faut d'abord déterminer le répertoire où est le module grâce à la fonction `split `_ -du module -`os.path `_. +du module :mod:`os.path`. Le programme suivant illustre cette possibilité en proposant une fonction qui importe un module connaissant le nom du fichier qui le contient. Il ne faut pas oublier d'enlever l'extension et ne pas garder aucun répertoire. @@ -414,8 +412,8 @@ Il ne faut pas oublier d'enlever l'extension et ne pas garder aucun répertoire. Liste des modules importés -------------------------- -Le dictionnaire `modules `_ -du module `sys `_ contient l'ensemble +Le dictionnaire :epkg:`sys.modules` +du module :mod:`sys` contient l'ensemble des modules importés. Le programme suivant affiche cette liste. .. runpython:: @@ -433,13 +431,13 @@ Lorsque le programme stipule l'import d'un module, *python* vérifie s'il n'est pas déjà présent dans cette liste. Dans le cas contraire, il l'importe. Chaque module n'est importé qu'une seule fois. La première instruction ``import module_exemple`` rencontrée introduit une nouvelle -entrée dans le dictionnaire `modules `_ : +entrée dans le dictionnaire :epkg:`sys.modules` : :: module_exemple -Le dictionnaire `modules `_ +Le dictionnaire :epkg:`sys.modules` peut être utilisé pour vérifier la présence d'un module ou lui assigner un autre identificateur. Un module est un objet qui n'autorise qu'une seule instance. @@ -458,7 +456,7 @@ Arborescence de modules, paquetage Lorsque le nombre de modules devient conséquent, il est parfois souhaitable de répartir tous ces fichiers dans plusieurs répertoires. Il faudrait alors inclure tous ces répertoires dans la liste -`sys.path `_ +:epkg:`sys.path` ce qui paraît fastidieux. *python* propose la définition de paquetage, ce dernier englobe tous les fichiers *python* d'un répertoire à condition que celui-ci contienne un fichier ``__init__.py`` qui peut @@ -567,7 +565,7 @@ susceptible de s'allonger au fur et à mesure du développement du langage - Lire le format HTML * - `importlib `_ - Pour importer des modules. - * - `math `_ + * - :mod:`math` - Fonctions mathématiques standard telles que `cos `_, `exp `_, @@ -583,7 +581,7 @@ susceptible de s'allonger au fur et à mesure du développement du langage structurées de façon complexe en une structure linéaire facilement enregistrable dans un fichier * - `profile `_ - Etudier le temps passé dans les fonctions d'un programme - * - `random `_ + * - :mod:`random` - Génération de nombres aléatoires * - `re `_ - Expressions régulières @@ -593,7 +591,7 @@ susceptible de s'allonger au fur et à mesure du développement du langage - Accès aux fonctionnalités du gestionnaire de base de données SQLite3 * - `string `_ - Manipulations des chaînes de caractères - * - `sys `_ + * - :mod:`sys` - Fonctions systèmes, fonctions liées au langage *python* * - `threading `_ - Utilisation de threads @@ -614,8 +612,8 @@ susceptible de s'allonger au fur et à mesure du développement du langage Certains de ces modules sont présentés dans les chapitres qui suivent. Le programme suivant par exemple utilise les modules -`random `_ -`math `_ +:mod:`random` +:mod:`math` pour estimer le nombre :math:`\pi`. Pour cela, on tire aléatoirement deux nombres :math:`x,y` dans l'intervalle :math:`[0,1]`, si :math:`\sqrt{x^2+y^2} \infegal 1`, @@ -692,7 +690,7 @@ comme celle qui fournit le module `tensorflow `_. Tout va souvent très vite. Le nombre de modifications est un critère assez simple pour s'assurer qu'un module -est maintenu : `commit `_. +est maintenu : `commit `_. La plupart des modules sont sur Github aujourd'hui. S'il ne l'est pas, passez votre chemin. @@ -709,5 +707,5 @@ Ce procédé marche la plupart du temps. Il échoue lorsque le module inclut des fichiers écrits dans un autre langage. L'installation dépend alors du système d'exploitation. Il est plus simple dans le cas d'installation des modules -précmopilés. Sous Windows, beaucoup sont accessibles sur cette page : -`Unofficial Windows Binaries for Python Extension Packages `_. +précompilés. La plupart sont disponibles sous cette forme +sur :epkg:`PyPi`, le site de publication des packages python. diff --git a/_doc/sphinxdoc/source/c_module/serialization.rst b/_doc/c_module/serialization.rst similarity index 92% rename from _doc/sphinxdoc/source/c_module/serialization.rst rename to _doc/c_module/serialization.rst index 25db4ed8..79b186d8 100644 --- a/_doc/sphinxdoc/source/c_module/serialization.rst +++ b/_doc/c_module/serialization.rst @@ -7,7 +7,7 @@ Sérialisation .. index:: sérialisation -La `sérialisation `_ est +La :epkg:`sérialisation` est un besoin fréquent depuis l'avènement d'internet. Une appplication web est souvent un assemblage de services indépendant qui s'échangent des informations complexes. Un service doit transmettre des données @@ -30,7 +30,7 @@ JSON ==== Un des premiers utilisés dans le monde internet est le format -`XML `_. +:epkg:`XML`. Le langage `HTML `_ suit la même logique que le format *XML*. Il peut représenter un assemblage de liste et de dictionnaires @@ -70,7 +70,7 @@ de dictionnaires puis à la convertir sous la forme d'une séquence d'octets. A -> B -> C; } -Le format `XML `_ +Le format :epkg:`XML` intervient lors de la seconde étape. Il est assez *verbeux*. La séquence d'octets ou plutôt de caractères qu'il produit est assez longue même une fois les espaces enlevés. On lui préfère le format :epkg:`JSON` @@ -104,8 +104,8 @@ La conversion inverse s'effectue comme suit. from json import load from io import StringIO - seq = '{"records": [{"nom": "Xavier", "pr\\u00e9nom": "Xavier", ' + \ - '"langages": [{"nom": "C++", "age": 40}, {"nom": "Python", "age": 20}]}]}' + seq = ('{"records": [{"nom": "Xavier", "pr\\u00e9nom": "Xavier", ' + + '"langages": [{"nom": "C++", "age": 40}, {"nom": "Python", "age": 20}]}]}') buffer = StringIO(seq) read = load(buffer) @@ -154,9 +154,9 @@ plus sérialisables par défaut. print(e) On peut néanmoins contourner l'obstacle en indiquant à la fonction -`dump `_ +:func:`json.dump` comment convertir l'instance en un assemblage de listes et de dictionnaires -avec la classe `JSONEncoder `_. +avec la classe :class:`json.JSONEncoder`. .. runpython:: :showcode: @@ -204,8 +204,7 @@ Et la relecture s'effectue comme suit : print(obj) Il existe des alternatives plus rapides au module -`json `_ -come le module :epkg:`ultrajson`. +:mod:`json` comme le module :epkg:`ultrajson`. Binaire ======= @@ -322,12 +321,7 @@ dans le language de votre choix. A -> B [label = "compilation"]; } -La suite est dans le notebook : - -.. toctree:: - :maxdepth: 1 - - ../notebooks/serialisation_protobuf +La suite est dans l'exemple :ref:`l-example-protobuf`. Sérialiser autre chose que des données ====================================== @@ -341,4 +335,4 @@ où cela est néanmoins possible sans trop de développement. .. toctree:: :maxdepth: 1 - ../notebooks/serialisation_examples + ../auto_examples/plot_serialisation_examples diff --git a/_doc/sphinxdoc/source/c_parallelisation/images/asyncapi.png b/_doc/c_parallelisation/images/asyncapi.png similarity index 100% rename from _doc/sphinxdoc/source/c_parallelisation/images/asyncapi.png rename to _doc/c_parallelisation/images/asyncapi.png diff --git a/_doc/sphinxdoc/source/c_parallelisation/images/pool.png b/_doc/c_parallelisation/images/pool.png similarity index 100% rename from _doc/sphinxdoc/source/c_parallelisation/images/pool.png rename to _doc/c_parallelisation/images/pool.png diff --git a/_doc/sphinxdoc/source/c_parallelisation/images/threadim1.png b/_doc/c_parallelisation/images/threadim1.png similarity index 100% rename from _doc/sphinxdoc/source/c_parallelisation/images/threadim1.png rename to _doc/c_parallelisation/images/threadim1.png diff --git a/_doc/sphinxdoc/source/c_parallelisation/images/threadim2.png b/_doc/c_parallelisation/images/threadim2.png similarity index 100% rename from _doc/sphinxdoc/source/c_parallelisation/images/threadim2.png rename to _doc/c_parallelisation/images/threadim2.png diff --git a/_doc/sphinxdoc/source/c_parallelisation/index.rst b/_doc/c_parallelisation/index.rst similarity index 78% rename from _doc/sphinxdoc/source/c_parallelisation/index.rst rename to _doc/c_parallelisation/index.rst index 963c0912..11bcca5e 100644 --- a/_doc/sphinxdoc/source/c_parallelisation/index.rst +++ b/_doc/c_parallelisation/index.rst @@ -18,20 +18,21 @@ les paragraphes suivantes. Il existe d'autres librairies qui ont été développés pour des usages spécifiques telles que -`joblib `_ qui est utilisé +`joblib `_ qui est utilisé par `scikit-learn `_. La librairie `gevent `_ est un équivalent -de la librairie `asyncio `_ +de la librairie :mod:`asyncio` qui a été intégrée à Python 3.4. Plus récemment, le package `uvloop `_ propose une accélération de deux à quatre fois par rapport à la librairie -`asyncio `_ : +:mod:`asyncio` : `uvloop: Blazing fast Python networking `_. Cette dernière librairie est utilisée par le module `sanic `_ qui implémenté un serveur web plus rapide que `flask `_. -La page `Parallel Processing in Python `_ +La page `Parallel Processing in Python +`_ passe en revue différentes stratégies de parallélisation pour l'implémentation de calculs numériques avec :epkg:`joblib`, :epkg:`cython`, :epkg:`OpenMP`. diff --git a/_doc/sphinxdoc/source/c_parallelisation/thread.rst b/_doc/c_parallelisation/thread.rst similarity index 95% rename from _doc/sphinxdoc/source/c_parallelisation/thread.rst rename to _doc/c_parallelisation/thread.rst index 936ef200..3a546485 100644 --- a/_doc/sphinxdoc/source/c_parallelisation/thread.rst +++ b/_doc/c_parallelisation/thread.rst @@ -19,7 +19,7 @@ maintenant vers la construction de processeurs multicoeurs, c'est-à-dire des machines capables d'exécuter des programmes simultanément, de maintenir plusieurs *fils d'exécution* en parallèle. -Les `threads `_ +Les :epkg:`threads` ou fils d'exécution ont trois usages principaux. Le premier est relié au `calcul distribué `_ ou calcul parallèle. Par exemple, le calcul d'une intégrale sur un intervalle peut être effectué sur @@ -769,11 +769,10 @@ Le module `threading `_ a beaucoup été utilisé mais d'autres modules ont été ajoutés à la distribution standard de python. -* `concurrent.futures `_ : +* :mod:`concurrent.futures` : le module propose une interface similaire pour paralléliser avec des threads ou des processus. La création des threads s'écrit plus rapidement. -* `asyncio `_ : - ce module fonctionne avec les mots-clés +* :mod:`asyncio` : ce module fonctionne avec les mots-clés `async, await `_ et il est particulièrement adapté à la parallélisation à des accès aux ressources. @@ -784,17 +783,17 @@ qui gère pas mal d'accès à Internet. concurrent.futures ++++++++++++++++++ -Le module `concurrent.futures `_ -implémente une classe `Executor `_ +Le module :mod:`concurrent.futures` +implémente une classe :class:`concurrent.futures.Executor` qui définit une interface pour l'exécution en parallèle. On peut soit : * soumettre l'exécution d'une fonction avec - `submit `_, + :meth:`concurrent.futures.Executor.submit` * ou soumettre l'exécution de la même fonction appliquée à séquence de jeux de paramètres - avec `map `_. + avec :meth:`concurrent.futures.Executor.map` Cette classe est dérivée en un -`ThreadPoolExecutor `_ +:class:`concurrent.futures.ThreadPoolExecutor` dont le principal argument *max_works* définit le nombre de threads à exécuter en parallèle. Je reproduis ici l'`exemple `_ de la documentation de *Python* qui détermine si un nombre est premier. @@ -958,18 +957,16 @@ Les `futures ou promesses font référence à un résultat dont le calcul est géré par un autre thread ou processus. Le résultat n'est pas prêt au moment où ce second thread démarre mais il le sera bientôt d'où son nom. On les retrouve en C# -`Programmation asynchrone avec Async et Await `_ +`Programmation asynchrone avec Async et Await +`_ ou C++ `std::async `_. Il y a deux objets *futures* en Python qui sont produits par différents jeux de fonctions. On ne créé jamais un *futures*, c'est toujours une fonction qui le fait. -* `concurrent.futures.Future `_ : - ils sont créés par le module - `concurrent.futures `_. +* :class:`concurrent.futures.Future` : ils sont créés par le module :mod:`concurrent.futures`. * `asyncio.future `_ : - ils sont créés par le module - `asyncio `_. + ils sont créés par le module :mod:`asyncio`. Les deux objets possèdent la même interface et sont presque compatibles. Cela dit, il vaut mieux éviter de les mélanger. Je cite la documentation : @@ -1032,7 +1029,7 @@ async - await - asyncio `asyncio `_ a fait émerger les mots-clés `async and await `_ qui font partie du langage depuis la version 3.5 tout comme elles font partie -d'autres langages comme `C# `_ +d'autres langages comme `C#/async `_ ou `C++ `_. Concrètement, ce n'est pas si difficile d'écrire une fonction @@ -1065,14 +1062,14 @@ de synchronisation si besoin. Le langage Python protège listes et dictionnaires par l'intermédiaire de ce verrou qui est unique pour toutes les listes afin de pouvoir gérer efficacement le -`garbage collector `_ +:epkg:`garbage collector` (voir module `gc `_). En conséquence, si le langage Python est multithread par design, dans les faits, il ne l'est presque pas car le *GIL* est sans cesse utilisé. Le notebook :ref:`gilexamplerst` finira de vous convaincre. -cython -++++++ +cython : un mélange de python et C +++++++++++++++++++++++++++++++++++ Tout est possible avec le langage C même si `cython `_ @@ -1083,7 +1080,7 @@ Plus de liberté veut dire aussi plus d'attention à apporter au code. La page `Using parallelism `_ donne quelques exemples simples de parallélisation. Il est plus facile de paralléliser Python avec un autre langage -(voir aussi `Parallelizing numpy array loops with Cython and OpenMP `_). +(voir aussi `Parallelizing numpy array loops with Cython and OpenMP `_). C#, Java ++++++++ @@ -1098,7 +1095,7 @@ qui peut être utilisé via le module `py4j `_, `pyjnius `_. Les threads sont plus faciles à implémenter dans ces langages -même si le `garbage collector `_ +même si le :epkg:`garbage collector` peut nuire aux performances. Bibliographie @@ -1106,4 +1103,4 @@ Bibliographie *articles* -* `Aynschonous API for Python `_ +* `Async API for Python `_ diff --git a/_doc/sphinxdoc/source/c_regex/index.rst b/_doc/c_regex/index.rst similarity index 100% rename from _doc/sphinxdoc/source/c_regex/index.rst rename to _doc/c_regex/index.rst diff --git a/_doc/sphinxdoc/source/c_regex/regex.rst b/_doc/c_regex/regex.rst similarity index 93% rename from _doc/sphinxdoc/source/c_regex/regex.rst rename to _doc/c_regex/regex.rst index fe2b2a7e..3b2cc8fb 100644 --- a/_doc/sphinxdoc/source/c_regex/regex.rst +++ b/_doc/c_regex/regex.rst @@ -13,12 +13,12 @@ A quoi ça sert ? ================ Chercher un mot dans un texte est une tâche facile, c'est l'objectif -de la méthode `find `_ +de la méthode :meth:`str.find` attachée aux chaînes de caractères, elle suffit encore lorsqu'on cherche un mot au pluriel ou au singulier mais il faut l'appeler au moins deux fois pour chercher ces deux formes. Pour des expressions plus -compliquées, il est conseillé d'utiliser les -`expressions régulières `_. +compliquées, il est conseillé d'utiliser une +`expression régulière `_. C'est une fonctionnalité qu'on retrouve dans beaucoup de langages. C'est une forme de grammaire qui permet de rechercher des expressions. @@ -53,10 +53,10 @@ ce qu'on précise avec des parenthèses : [0-3]?[0-9]/[0-1]?[0-9]/([0-2][0-9])?[0-9][0-9] -Le module `re `_ +Le module :mod:`re` gère les expressions régulières, celui-ci traite différemment les parties de l'expression régulière qui sont entre parenthèses de celles qui ne le sont pas : c'est un moyen -de dire au module `re `_ +de dire au module :mod:`re` que nous nous intéressons à telle partie de l'expression qui est signalée entre parenthèses. Comme la partie qui nous intéresse - une date - concerne l'intégralité de l'expression régulière, @@ -224,15 +224,14 @@ l'expression *Xavier Dupont* ou *M. Dupont* s'écrira : ``(Xavier)|(M[.]) Dupont Fonctions --------- -La fonction `compile `_ -du module `re `_ +La fonction :func:`re.compile` +du module :mod:`re` permet de construire un objet "expression régulière". A partir de cet objet, on peut vérifier la correspondance entre une expression régulière et une chaîne -de caractères (méthode `match `_). -On peut chercher une expression régulière -(méthode `search `_). +de caractères (méthode :func:`re.match`). +On peut chercher une expression régulière (méthode :func:`re.search`). On peut aussi remplacer une expression régulière par une chaîne de caractères -(méthode `sub `_). +(méthode :func:`re.sub`). .. list-table:: :widths: 5 10 @@ -268,10 +267,8 @@ On peut aussi remplacer une expression régulière par une chaîne de caractère - Chaîne de caractères associée à l'expression régulière. C'est un attribut. Ces méthodes et attributs qui s'appliquent à un objet de type "expression régulière" -retourné par la fonction `compile `_. -Les méthodes `search `_ -et `match `_ -retournent toutes des objets `Match `_ : +retourné par la fonction :func:`re.compile`. Les méthodes :func:`re.search` +et :func:`re.match` retournent toutes des objets :func:`re.match` : .. runpython:: :showcode: @@ -298,10 +295,8 @@ retournent toutes des objets `Match `_ -qui est le résultat des méthodes `search `_ -et `match `_. +Ces méthodes qui s'appliquent à un objet de type :func:`re.match` +qui est le résultat des méthodes :func:`re.search` et :func:`re.match`. Les groupes sont des sous-parties de l'expression régulière, chacune d'entre elles incluses entre parenthèses. Le énième correspond au groupe qui suit la énième parenthèse ouvrante. Le premier groupe a pour indice 1. diff --git a/_doc/sphinxdoc/source/c_resume/conseil_programmes.rst b/_doc/c_resume/conseil_programmes.rst similarity index 100% rename from _doc/sphinxdoc/source/c_resume/conseil_programmes.rst rename to _doc/c_resume/conseil_programmes.rst diff --git a/_doc/sphinxdoc/source/c_resume/index.rst b/_doc/c_resume/index.rst similarity index 100% rename from _doc/sphinxdoc/source/c_resume/index.rst rename to _doc/c_resume/index.rst diff --git a/_doc/sphinxdoc/source/c_resume/python_sheet.rst b/_doc/c_resume/python_sheet.rst similarity index 99% rename from _doc/sphinxdoc/source/c_resume/python_sheet.rst rename to _doc/c_resume/python_sheet.rst index 286da934..c7e62952 100644 --- a/_doc/sphinxdoc/source/c_resume/python_sheet.rst +++ b/_doc/c_resume/python_sheet.rst @@ -535,8 +535,8 @@ Il existe un raccourci pour les intervalles : if 5 < x and x < 10 : # peut être écrit : if 5 < x < 10 : ... -Boucles -+++++++ +for ou while +++++++++++++ Il y a deux types de boucles, la boucle ``for`` parcourt un ensemble, la boucle ``while`` continue tant qu'une condition est vraie. @@ -935,8 +935,8 @@ le langage python, ils commencent et terminent par ``__``. self.att4 = att1 * att2 * att3 def __add__ (self, a) : - return ma_classe (self.att1 + a.att1, self.att2 + a.att2, \ - self.att3 + a.att3, self.att4 + a.att4) + return ma_classe (self.att1 + a.att1, self.att2 + a.att2, + self.att3 + a.att3, self.att4 + a.att4) a = ma_classe (1,2,3) b = ma_classe (4,5,6) @@ -1391,8 +1391,10 @@ L'exemple suivant regroupe tous ces cas. self.f = f def __str__(self) : - return """exception AucunChiffre, lancée depuis la fonction """ + self.f + \ - " avec le paramètre " + self.s + return ( + f"exception AucunChiffre, lancée depuis la fonction {self.f} " + f"avec le paramètre {self.s}" + ) def conversion (s) : """conversion d'une chaîne de caractères en entier""" @@ -1430,7 +1432,7 @@ pour accéder à un caractère, on procède comme pour une liste. Guillemets ou pas ^^^^^^^^^^^^^^^^^ -Doit-on mettre des guillemets ou non~? +Doit-on mettre des guillemets ou non ? :: @@ -1462,7 +1464,7 @@ Boucles Les deux programmes suivant sont équivalents. La seule différence réside dans l'écriture dans la boucle ``for`` -qui utilise dans le premier cas la fonction ``range`` et dans l'autre non. +qui utilise dans le premier cas la fonction :epkg:`range` et dans l'autre non. :: @@ -1471,7 +1473,7 @@ qui utilise dans le premier cas la fonction ``range`` et dans l'autre non. for i in range (0, len(l)) : up.append ( l [i].upper() ) -Lorsqu'on utilise la fonction ``range``, on dispose lors +Lorsqu'on utilise la fonction :epkg:`range`, on dispose lors de la boucle de deux informations, l'indice ``i`` et l'élément ``l [i]``. Si l'indice n'est pas utile, il est possible de simplifier la boucle comme suit. @@ -1482,7 +1484,7 @@ Si l'indice n'est pas utile, il est possible de simplifier la boucle comme suit. for m in l : up.append ( m.upper() ) -En général, on se sert de la boucle qui utilise la fonction ``range`` dans deux cas : +En général, on se sert de la boucle qui utilise la fonction :epkg:`range` dans deux cas : #. On souhaite faire des opérations sur les éléments qui précèdent ou suivent l'élément en question, ce qui nécessite de connaître l'indice. @@ -1505,9 +1507,6 @@ aurait si la liste était vide. for m in l : s += m # concaténation des mots en une seule chaîne de caractères -Fonctions -+++++++++ - Différence entre ``print`` et ``return`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/_doc/conf.py b/_doc/conf.py new file mode 100644 index 00000000..40354cce --- /dev/null +++ b/_doc/conf.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- +import os +import sys + +from sphinx_runpython.conf_helper import has_dvipng, has_dvisvgm +from sphinx_runpython.github_link import make_linkcode_resolve + +from teachpyx import __version__ + +extensions = [ + "nbsphinx", + "sphinx.ext.autodoc", + "sphinx.ext.coverage", + "sphinx.ext.githubpages", + "sphinx.ext.ifconfig", + "sphinx.ext.intersphinx", + "sphinx.ext.linkcode", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx_gallery.gen_gallery", + "sphinx_issues", + "sphinx_runpython.blocdefs.sphinx_exref_extension", + "sphinx_runpython.blocdefs.sphinx_faqref_extension", + "sphinx_runpython.blocdefs.sphinx_mathdef_extension", + "sphinx_runpython.epkg", + "sphinx_runpython.gdot", + "sphinx_runpython.runpython", + "sphinxcontrib.blockdiag", + "matplotlib.sphinxext.plot_directive", +] + +if has_dvisvgm(): + extensions.append("sphinx.ext.imgmath") + imgmath_image_format = "svg" +elif has_dvipng(): + extensions.append("sphinx.ext.pngmath") + imgmath_image_format = "png" +else: + extensions.append("sphinx.ext.mathjax") + +templates_path = ["_templates"] +html_logo = "_static/project_ico.png" +source_suffix = ".rst" +master_doc = "index" +project = "teachpyx" +copyright = "2016-2023, Xavier Dupré" +author = "Xavier Dupré" +version = __version__ +release = __version__ +language = "fr" +exclude_patterns = ["auto_examples/*.ipynb"] +pygments_style = "sphinx" +todo_include_todos = True +nbsphinx_execute = "never" + +html_theme = "pydata_sphinx_theme" +html_theme_path = ["_static"] +html_theme_options = {} +html_sourcelink_suffix = "" +html_static_path = ["_static"] + +issues_github_path = "sdpython/teachpyx" + +# The following is used by sphinx.ext.linkcode to provide links to github +linkcode_resolve = make_linkcode_resolve( + "teachpyx", + ( + "https://github.com/sdpython/teachpyx/" + "blob/{revision}/{package}/" + "{path}#L{lineno}" + ), +) + +latex_elements = { + "papersize": "a4", + "pointsize": "10pt", + "title": project, +} + +mathjax3_config = {"chtml": {"displayAlign": "left"}} + +intersphinx_mapping = { + "onnx": ("https://onnx.ai/onnx/", None), + "matplotlib": ("https://matplotlib.org/", None), + "numpy": ("https://numpy.org/doc/stable", None), + "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), + "python": (f"https://docs.python.org/{sys.version_info.major}", None), + "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "sklearn": ("https://scikit-learn.org/stable/", None), + "sklearn-onnx": ("https://onnx.ai/sklearn-onnx/", None), + "torch": ("https://pytorch.org/docs/stable/", None), +} + +# Check intersphinx reference targets exist +nitpicky = True +# See also scikit-learn/scikit-learn#26761 +nitpick_ignore = [ + ("py:class", "False"), + ("py:class", "True"), + ("py:class", "pipeline.Pipeline"), + ("py:class", "default=sklearn.utils.metadata_routing.UNCHANGED"), +] + +sphinx_gallery_conf = { + # path to your examples scripts + "examples_dirs": os.path.join(os.path.dirname(__file__), "examples"), + # path where to save gallery generated examples + "gallery_dirs": "auto_examples", + "ignore_pattern": "schema_pb.*[.]py", +} + +# next + +preamble = """ +\\usepackage{etex} +\\usepackage{fixltx2e} % LaTeX patches, \\textsubscript +\\usepackage{cmap} % fix search and cut-and-paste in Acrobat +\\usepackage[raccourcis]{fast-diagram} +\\usepackage{titlesec} +\\usepackage{amsmath} +\\usepackage{amssymb} +\\usepackage{amsfonts} +\\usepackage{graphics} +\\usepackage{epic} +\\usepackage{eepic} +%\\usepackage{pict2e} +%%% Redefined titleformat +\\setlength{\\parindent}{0cm} +\\setlength{\\parskip}{1ex plus 0.5ex minus 0.2ex} +\\newcommand{\\hsp}{\\hspace{20pt}} +\\newcommand{\\acc}[1]{\\left\\{#1\\right\\}} +\\newcommand{\\cro}[1]{\\left[#1\\right]} +\\newcommand{\\pa}[1]{\\left(#1\\right)} +\\newcommand{\\R}{\\mathbb{R}} +\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}} +%\\titleformat{\\chapter}[hang]{\\Huge\\bfseries\\sffamily}{\\thechapter\\hsp}{0pt}{\\Huge\\bfseries\\sffamily} + +\\usepackage[all]{xy} +\\newcommand{\\vecteur}[2]{\\pa{#1,\\dots,#2}} +\\newcommand{\\N}[0]{\\mathbb{N}} +\\newcommand{\\indicatrice}[1]{ {1\\!\\!1}_{\\acc{#1}} } +\\newcommand{\\infegal}[0]{\\leqslant} +\\newcommand{\\supegal}[0]{\\geqslant} +\\newcommand{\\ensemble}[2]{\\acc{#1,\\dots,#2}} +\\newcommand{\\fleche}[1]{\\overrightarrow{ #1 }} +\\newcommand{\\intervalle}[2]{\\left\\{#1,\\cdots,#2\\right\\}} +\\newcommand{\\independant}[0]{\\perp \\!\\!\\! \\perp} +\\newcommand{\\esp}{\\mathbb{E}} +\\newcommand{\\espf}[2]{\\mathbb{E}_{#1}\\pa{#2}} +\\newcommand{\\var}{\\mathbb{V}} +\\newcommand{\\pr}[1]{\\mathbb{P}\\pa{#1}} +\\newcommand{\\loi}[0]{{\\cal L}} +\\newcommand{\\vecteurno}[2]{#1,\\dots,#2} +\\newcommand{\\norm}[1]{\\left\\Vert#1\\right\\Vert} +\\newcommand{\\norme}[1]{\\left\\Vert#1\\right\\Vert} +\\newcommand{\\scal}[2]{\\left<#1,#2\\right>} +\\newcommand{\\dans}[0]{\\rightarrow} +\\newcommand{\\partialfrac}[2]{\\frac{\\partial #1}{\\partial #2}} +\\newcommand{\\partialdfrac}[2]{\\dfrac{\\partial #1}{\\partial #2}} +\\newcommand{\\trace}[1]{tr\\pa{#1}} +\\newcommand{\\sac}[0]{|} +\\newcommand{\\abs}[1]{\\left|#1\\right|} +\\newcommand{\\loinormale}[2]{{\\cal N} \\pa{#1,#2}} +\\newcommand{\\loibinomialea}[1]{{\\cal B} \\pa{#1}} +\\newcommand{\\loibinomiale}[2]{{\\cal B} \\pa{#1,#2}} +\\newcommand{\\loimultinomiale}[1]{{\\cal M} \\pa{#1}} +\\newcommand{\\variance}[1]{\\mathbb{V}\\pa{#1}} +\\newcommand{\\intf}[1]{\\left\\lfloor #1 \\right\\rfloor} +""" + +epkg_dictionary = { + "ACP": "https://fr.wikipedia.org/wiki/Analyse_en_composantes_principales", + "AESA": "https://tavianator.com/aesa/", + "algorithme": "https://fr.wikipedia.org/wiki/Algorithme", + "algorithmes de tri": "https://fr.wikipedia.org/wiki/Algorithme_de_tri", + "algorithmes numériques": "https://fr.wikipedia.org/wiki/Numerical_Recipes", + "API REST": "https://fr.wikipedia.org/wiki/Representational_state_transfer", + "Anaconda": "https://continuum.io/downloads", + "ApproximateNMFPredictor": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/mlinsights/mlmodel/anmf_predictor.html", + "AUC": "https://en.wikipedia.org/wiki/Receiver_operating_characteristic#Area_under_the_curve", + "Awesome Python": "https://awesome-python.com/", + "B+ tree": "https://en.wikipedia.org/wiki/B%2B_tree", + "BLAS": "https://www.netlib.org/blas/", + "Branch and Bound": "https://en.wikipedia.org/wiki/Branch_and_bound", + "bytearray": "https://docs.python.org/3/library/functions.html#bytearray", + "C++": "https://fr.wikipedia.org/wiki/C%2B%2B", + "copy": "https://docs.python.org/3/library/copy.html?highlight=copy#copy.copy", + "cloudpickle": "https://github.com/cloudpipe/cloudpickle", + "Custom Criterion for DecisionTreeRegressor": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/notebooks/piecewise_linear_regression_criterion.html", + "cython": "https://cython.org/", + "DecisionTreeClassifier": "https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html", + "DecisionTreeRegressor optimized for Linear Regression": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/notebooks/piecewise_linear_regression_criterion.html", + "deepcopy": "https://docs.python.org/3/library/copy.html?highlight=copy#copy.deepcopy", + "dill": "https://dill.readthedocs.io/en/latest/", + "dir": "https://docs.python.org/3/library/functions.html?highlight=dir#dir", + "dot": "https://fr.wikipedia.org/wiki/DOT_(langage)", + "encoding": "https://fr.wikipedia.org/wiki/Codage_des_caract%C3%A8res", + "eval": "https://docs.python.org/3/library/functions.html?highlight=id#eval", + "Excel": "https://fr.wikipedia.org/wiki/Microsoft_Excel", + "format": "https://pyformat.info/", + "format style": "https://pyformat.info/", + "garbage collector": "https://fr.wikipedia.org/wiki/Ramasse-miettes_(informatique)", + "Holm-Bonferroni method": "https://en.wikipedia.org/wiki/Holm%E2%80%93Bonferroni_method", + "HTML": "https://fr.wikipedia.org/wiki/Hypertext_Markup_Language", + "ICML 2016": "https://icml.cc/2016/index.html", + "indentation": "https://fr.wikipedia.org/wiki/Style_d%27indentation", + "issubclass": "https://docs.python.org/3/library/functions.html?highlight=issubclass#issubclass", + "joblib": "https://joblib.readthedocs.io/en/stable/", + "JSON": "https://en.wikipedia.org/wiki/JSON", + "jupyter": "https://jupyter.org/", + "KMeans": "https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html", + "LAESA": "https://tavianator.com/aesa/", + "LAPACK": "http://www.netlib.org/lapack/", + "Method Resolution Order": "https://www.python.org/download/releases/2.3/mro/", + "miniconda": "https://docs.conda.io/en/latest/miniconda.html", + "Miniconda": "https://docs.conda.io/en/latest/miniconda.html", + "mlinsights": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/index.html", + "mlstatpy": "https://sdpython.github.io/doc/mlstatpy/dev/", + "numpy": ( + "https://www.numpy.org/", + ("https://docs.scipy.org/doc/numpy/reference/generated/numpy.{0}.html", 1), + ("https://docs.scipy.org/doc/numpy/reference/generated/numpy.{0}.{1}.html", 2), + ), + "OpenMP": "https://www.openmp.org/", + "pandas": ( + "https://pandas.pydata.org/pandas-docs/stable/", + ("https://pandas.pydata.org/pandas-docs/stable/generated/pandas.{0}.html", 1), + ( + "https://pandas.pydata.org/pandas-docs/stable/generated/pandas.{0}.{1}.html", + 2, + ), + ), + "PiecewiseTreeRegressor": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/mlinsights/mlmodel/" + "piecewise_tree_regression.html#mlinsights.mlmodel.piecewise_tree_regression.PiecewiseTreeRegressor", + "Pillow": "https://pillow.readthedocs.io/en/stable/", + "Predictable t-SNE": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/notebooks/predictable_tsne.html", + "printf-style String Formatting": "https://docs.python.org/3/library/stdtypes.html#old-string-formatting", + "programmation impérative": "https://fr.wikipedia.org/wiki/Programmation_imp%C3%A9rative", + "programmation fonctionnelle": "https://fr.wikipedia.org/wiki/Programmation_fonctionnelle", + "protobuf": "https://protobuf.dev/", + "pypi": "https://pypi.org/", + "PyPi": "https://pypi.org/", + "pylint": "https://www.pylint.org/", + "python": "https://www.python.org/", + "Python": "https://www.python.org/", + "QuantileLinearRegression": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/mlinsights/mlmodel/quantile_regression.html#mlinsights.mlmodel.quantile_regression.QuantileLinearRegression", + "R-tree": "https://en.wikipedia.org/wiki/R-tree", + "R* tree": "https://en.wikipedia.org/wiki/R*_tree", + "range": "https://docs.python.org/3/library/functions.html?highlight=map#func-range", + "Regression with confidence interval": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/notebooks/regression_confidence_interval.html", + "relu": "https://en.wikipedia.org/wiki/Rectifier_(neural_networks)", + "ROC": "https://fr.wikipedia.org/wiki/Courbe_ROC", + "scikit-learn": "https://scikit-learn.org/stable/index.html", + "sérialisation": "https://fr.wikipedia.org/wiki/S%C3%A9rialisation", + "sklearn": "https://scikit-learn.org/stable/index.html", + "sklearn-onnx": "https://onnx.ai/sklearn-onnx/", + "statsmodels": "http://www.statsmodels.org/stable/index.html", + "SVD": "https://fr.wikipedia.org/wiki/D%C3%A9composition_en_valeurs_singuli%C3%A8res", + "sys.modules": "https://docs.python.org/3/library/sys.html?highlight=modules#sys.modules", + "sys.path": "https://docs.python.org/3/library/sys.html#sys.path", + "teachpyx": "https://sdpython.github.io/doc/teachpyx/dev/", + "threads": "https://fr.wikipedia.org/wiki/Thread_(informatique)", + "tkinter": "https://docs.python.org/3/library/tk.html", + "tqdm": "https://tqdm.github.io/", + "ultrajson": "https://github.com/ultrajson/ultrajson", + "ujson": "https://github.com/ultrajson/ultrajson", + "Visual Studio Code": "https://code.visualstudio.com/", + "Visualize a scikit-learn pipeline": "http://www.xavierdupre.fr/app/mlinsights/helpsphinx/notebooks/visualize_pipeline.html", + "X-tree": "https://en.wikipedia.org/wiki/X-tree", + "XML": "https://fr.wikipedia.org/wiki/Extensible_Markup_Language", + "wikipedia dumps": "https://dumps.wikimedia.org/frwiki/latest/", + "wxPython": "https://wxpython.org/", +} + +epkg_dictionary.update( + { + "tkinter.Button": "https://tkdocs.com/tutorial/button.html", + "tkinter.Button.config": "https://tkdocs.com/tutorial/button.html", + "tkinter.Canvas": "https://tkdocs.com/tutorial/canvas.html", + "tkinter.Canvas.create_line": "https://tkdocs.com/tutorial/canvas.html", + "tkinter.Canvas.create_rectangle": "https://tkdocs.com/tutorial/canvas.html", + "tkinter.Canvas.create_text": "https://tkdocs.com/tutorial/canvas.html", + "tkinter.CheckButton": "https://tkdocs.com/tutorial/widgets.html#checkbutton", + "tkinter.CheckButton.config": "https://tkdocs.com/tutorial/widgets.html#checkbutton", + "tkinter.Entry": "https://tkdocs.com/pyref/entry.html", + "tkinter.Entry.delete": "https://tkdocs.com/pyref/entry.html", + "tkinter.Entry.config": "https://tkdocs.com/pyref/entry.html", + "tkinter.Entry.get": "https://tkdocs.com/pyref/entry.html", + "tkinter.Entry.insert": "https://tkdocs.com/pyref/entry.html", + "tkinter.Event": "https://tkdocs.com/tutorial/eventloop.html", + "tkinter.Frame": "https://tkdocs.com/tutorial/widgets.html#frame", + "tkinter.IntVar": "https://tkdocs.com/pyref/intvar.html", + "tkinter.Label": "https://tkdocs.com/tutorial/widgets.html#label", + "tkinter.Label.after_cancel": "https://tkdocs.com/tutorial/widgets.html#label", + "tkinter.ListBox": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.config": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.curselection": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.delete": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.get": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.insert": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.itemconfig": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.select_all": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.select_clear": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.select_get": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.ListBox.select_set": "https://tkdocs.com/tutorial/widgets.html#listbox", + "tkinter.Menu": "https://tkdocs.com/tutorial/widgets.html#menu", + "tkinter.Menu.add_command": "https://tkdocs.com/tutorial/widgets.html#menu", + "tkinter.Menu.add_cascade": "https://tkdocs.com/tutorial/widgets.html#menu", + "tkinter.Menu.delete": "https://tkdocs.com/tutorial/widgets.html#menu", + "tkinter.RadioButton": "https://tkdocs.com/tutorial/widgets.html#radiobutton", + "tkinter.Text": "https://tkdocs.com/tutorial/text.html", + "tkinter.Text.config": "https://tkdocs.com/tutorial/text.html", + "tkinter.Text.delete": "https://tkdocs.com/tutorial/text.html", + "tkinter.Text.get": "https://tkdocs.com/tutorial/text.html", + "tkinter.Text.insert": "https://tkdocs.com/tutorial/text.html", + "tkinter.Toplevel": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.deiconify": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.destroy": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.geometry": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.iconify": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.resizable": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.title": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.Toplevel.withdraw": "https://tkdocs.com/pyref/toplevel.html", + "tkinter.tix.DirTree": "https://pythonbasics.org/tkinter-filedialog/", + "tkinter.tix.FileSelectBox": "https://pythonbasics.org/tkinter-filedialog/", + "tkinter.ttk.Combobox": "https://tkdocs.com/pyref/ttk_combobox.html", + "tkinter.ttk.Notebook": "https://tkdocs.com/pyref/ttk_notebook.html", + "tkinter.ttk.Progressbar": "https://tkdocs.com/pyref/ttk_progressbar.html", + "tkinter.ttk.Treeview": "https://tkdocs.com/pyref/ttk_treeview.html", + "tkinter.Widget.bind": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.bind_all": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.focus": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.focus_set": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.grid": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.grid_forget": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.pack": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.pack_forget": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.place": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.place_forget": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.unbind": "https://tkdocs.com/tutorial/index.html", + "tkinter.Widget.unbind_all": "https://tkdocs.com/tutorial/index.html", + } +) + +imgmath_latex_preamble = preamble +latex_elements["preamble"] = imgmath_latex_preamble diff --git a/_doc/sphinxdoc/source/defthe_index.rst b/_doc/defthe_index.rst similarity index 100% rename from _doc/sphinxdoc/source/defthe_index.rst rename to _doc/defthe_index.rst diff --git a/_doc/examples/plot_float_and_double_rouding.py b/_doc/examples/plot_float_and_double_rouding.py new file mode 100644 index 00000000..8d35541f --- /dev/null +++ b/_doc/examples/plot_float_and_double_rouding.py @@ -0,0 +1,279 @@ +# coding: utf-8 +""" +================ +Float Conversion +================ + +I came up with the following question +:math:`(float64)x < (float64)y \Longrightarrow (float32) x < (float32)y`? +What is the probability this holds? + +Probability (float64)x == (float32)x +==================================== + +Let's evaluate how many time we draw a random double +number equal to its float conversion. +""" + +import random +import numpy +import pandas +import matplotlib.pyplot as plt + + +rnd = numpy.random.random(100000000) +rnd.shape, rnd.dtype + +###################################### +# + +rnd32 = rnd.astype(numpy.float32).astype(numpy.float64) +equal = (rnd == rnd32).sum() +equal + + +###################################### +# It is very low. Let's check the reverse is true. + + +rnd32b = rnd32.astype(numpy.float64).astype(numpy.float32) +equal = (rnd32b == rnd32).sum() +equal + + +###################################### +# Let's study the distribution of the difference. + + +delta = rnd - rnd32 +numpy.min(delta), numpy.max(delta) + + +###################################### +# + +numpy.min(rnd), numpy.max(rnd) + + +###################################### +# + + +plt.hist(delta, bins=1000) + + +###################################### +# We finally check that double operations between float numpers remain floats. + + +for i in range(0, 100000): + i, j = random.randint(0, len(rnd32) - 1), random.randint(0, len(rnd32) - 1) + d32 = numpy.float64(rnd32[i] * rnd32[j]) + d64 = numpy.float64(rnd32[i]) * numpy.float64(rnd32[j]) + if d32 != d64: + raise Exception( + "Issue with somme={0} = {1} + {2}".format( + rnd32[i] + rnd32[j], rnd32[i], rnd32[j] + ) + ) + + +###################################### +# Interval length distribution +# ============================ +# +# Let's imagine now we want to define an intervalle in which a +# double is converted to the same float. Let's find out about it length. + + +def find_interval(x): + dx = numpy.abs(x - numpy.float32(x)) # usually not zero + dx /= 100 + f = numpy.float32(x) + x1 = x + while numpy.float32(x1) == f: + x1 -= dx + x2 = x + while numpy.float32(x2) == f: + x2 += dx + return x1 + dx, x2 - dx + + +length = numpy.zeros((2000,)) +for i in range(length.shape[0]): + x = rnd[i] + x1, x2 = find_interval(x) + length[i] = x2 - x1 + +min(length), max(length) + + +###################################### + +plt.hist(length, bins=50) + + +###################################### +# So we can approximate this interval by something like this: + + +ql = numpy.sort(length)[int(length.shape[0] * 0.8)] +ql + + +###################################### +# An answer to the initial question +# ================================= +# +# Let's estimate +# :math:`\mathbb{P}\left(x_{64} < y_{64} \Longrightarrow x_{32} +# < y_{32} \; | \; |x-y| \leqslant d\right)` ? + + +def inf_strict(x, y): + f1 = x < y + f2 = numpy.float32(x) < numpy.float32(y) + return f1, f2 + + +def count_events(fct): + rows = [] + for di in range(1, 1001): + d = di * ql / 100 + total = 0 + ok = 0 + rnd = numpy.random.random((2000 * 3,)) + for i in range(0, rnd.shape[0], 3): + s = -1 if rnd[i + 2] < 0.5 else 1 + x, y = rnd[i], rnd[i] + rnd[i + 1] * d * s + f1, f2 = fct(x, y) + if f1: + total += 1 + if f2: + ok += 1 + if (di + 10) % 100 == 0: + print(di, d, ":", ok, total) + rows.append(dict(d=d, ratio=ok * 1.0 / total, total=total)) + + return pandas.DataFrame(rows) + + +df = count_events(inf_strict) +df.head() + + +###################################### + +df.plot(x="d", y="ratio") + + +###################################### + +df.plot(x="d", y="ratio", logx=True) + + +###################################### +# An answer to a similar question: what about not strict comparison? +# ================================================================== +# +# Let's estimate +# :math:`\mathbb{P}\left(x_{64} \leqslant y_{64} \Longrightarrow x_{32} +# \leqslant y_{32} \; | \; |x-y| \leqslant d\right)` ? + + +def inf_equal(x, y): + f1 = x <= y + f2 = numpy.float32(x) <= numpy.float32(y) + return f1, f2 + + +df2 = count_events(inf_equal) +df2.head() + + +###################################### +# + +ax = df.plot(x="d", y="ratio", logx=True, label="<") +df2.plot(x="d", y="ratio", logx=True, label="<=", ax=ax) + + +###################################### +# + + +def sup_strict(x, y): + f1 = x > y + f2 = numpy.float32(x) > numpy.float32(y) + return f1, f2 + + +df3 = count_events(sup_strict) +df3.head() + + +###################################### +# + +ax = df.plot(x="d", y="ratio", logx=True, label="<") +df2.plot(x="d", y="ratio", logx=True, label="<=", ax=ax) +df3.plot(x="d", y="ratio", logx=True, label=">", ax=ax) + + +###################################### +# + + +def sup_equal(x, y): + f1 = x >= y + f2 = numpy.float32(x) >= numpy.float32(y) + return f1, f2 + + +df4 = count_events(sup_equal) +df4.head() + + +###################################### +# + +ax = df.plot(x="d", y="ratio", logx=True, label="<") +df2.plot(x="d", y="ratio", logx=True, label="<=", ax=ax) +df3.plot(x="d", y="ratio", logx=True, label=">", ax=ax) +df4.plot(x="d", y="ratio", logx=True, label=">=", ax=ax) + + +###################################### +# + + +def inf_strict_neg(x, y): + f1 = (-x) >= (-y) + f2 = (-numpy.float32(x)) >= (-numpy.float32(y)) + return f1, f2 + + +dfn = count_events(inf_strict_neg) +dfn.head() + + +###################################### +# + +ax = df.plot(x="d", y="ratio", logx=True, label="<") +dfn.plot(x="d", y="ratio", logx=True, label="-1 x >=", ax=ax) + + +###################################### +# Conclusion +# ========== +# +# The result is expected. As soon as two float are rounded to the same value, +# the strict inequality no longer holds. However, if you need to write a +# code which has to handle double and float (in a template for example), +# you should use not strict inequalities. It is easier to compare the results +# but you should read some article like `Is < faster than <=? +# `_. +# According to +# `Processing costs of non-strict versus strict comparison +# `_, ``<`` is 5-10% faster than ``<=``. diff --git a/_doc/examples/plot_gil_example.py b/_doc/examples/plot_gil_example.py new file mode 100644 index 00000000..935cf4c6 --- /dev/null +++ b/_doc/examples/plot_gil_example.py @@ -0,0 +1,86 @@ +# coding: utf-8 +""" + +.. _gilexamplerst: + +====== +Le GIL +====== + +Le GIL ou `Global Interpreter Lock `_ +est un verrou unique auquel l'interpréteur Python fait appel constamment +pour protéger tous les objets qu'il manipule contre des accès concurrentiels. + +Deux listes en parallel +======================= + +On mesure le temps nécessaire pour créer deux liste et comparer ce +temps avec celui que cela prendrait en parallèle. +""" +import timeit +import time +from concurrent.futures import ThreadPoolExecutor + + +def create_list(n): + res = [] + for i in range(n): + res.append(i) + return res + + +timeit.timeit("create_list(100000)", globals=globals(), number=100) + +###################################### +# En parallèle avec le module `concurrent.futures +# `_ +# et deux appels à la même fonction. + + +def run2(nb): + with ThreadPoolExecutor(max_workers=2) as executor: + for res in executor.map(create_list, [nb, nb + 1]): + pass + + +timeit.timeit("run2(100000)", globals=globals(), number=100) + + +###################################### +# C'est plus long que si les calculs étaient lancés les uns après les autres. +# Ce temps est perdu à synchroniser les deux threads bien que les +# deux boucles n'aient rien à échanger. Chaque thread passe son +# temps à attendre que l'autre ait terminé de mettre à jour sa +# liste et le *GIL* impose que ces mises à jour aient lieu une après l'autre. +# +# Un autre scénario +# ================= +# +# Au lieu de mettre à jour une liste, on va lancer un thread +# qui ne fait rien qu'attendre. Donc le *GIL* n'est pas impliqué. + + +def attendre(t=0.009): + time.sleep(t) + return None + + +timeit.timeit("attendre()", globals=globals(), number=100) + + +###################################### +# + + +def run3(t): + with ThreadPoolExecutor(max_workers=2) as executor: + for res in executor.map(attendre, [t, t + 0.001]): + pass + + +timeit.timeit("run3(0.009)", globals=globals(), number=100) + + +###################################### +# Les deux attentes se font en parallèle car le temps moyen est +# significativement inférieur à la somme des deux attentes. diff --git a/_doc/examples/plot_hypercube.py b/_doc/examples/plot_hypercube.py new file mode 100644 index 00000000..c1c06fb0 --- /dev/null +++ b/_doc/examples/plot_hypercube.py @@ -0,0 +1,385 @@ +# coding: utf-8 +""" + +.. _hypercuberst: + +============================= +Hypercube et autres exercices +============================= + +Exercices autour de tableaux en plusieurs dimensions et autres exercices. + +Q1 - triple récursivité +======================= + +Réécrire la fonction ``u`` de façon à ce qu'elle ne soit plus récurrente. +""" + + +def u(n): + if n <= 2: + return 1 + else: + return u(n - 1) + u(n - 2) + u(n - 3) + + +u(5) + +###################################### +# Le problème de cette écriture est que la fonction est triplement +# récursive et que son coût est aussi grand que la fonction elle-même. Vérifions. + + +compteur = [] + + +def u_st(n): + global compteur + compteur.append(n) + if n <= 2: + return 1 + else: + return u_st(n - 1) + u_st(n - 2) + u_st(n - 3) + + +u_st(5), compteur + + +###################################### +# La seconde liste retourne tous les *n* pour lesquels la fonction +# ``u_st`` a été appelée. + + +def u_non_recursif(n): + if n <= 2: + return 1 + u0 = 1 + u1 = 1 + u2 = 1 + i = 3 + while i <= n: + u = u0 + u1 + u2 + u0 = u1 + u1 = u2 + u2 = u + i += 1 + return u + + +u_non_recursif(5) + + +###################################### +# Q2 - comparaison de listes +# ========================== +# +# On considère deux listes d'entiers. La première est inférieure à la seconde +# si l'une des deux conditions suivantes est vérifiée : +# +# * les *n* premiers nombres sont égaux mais la première liste ne contient que +# *n* éléments tandis que la seconde est plus longue, +# * les *n* premiers nombres sont égaux mais que le :math:`n+1^{\text{ème}}` de la +# première liste est inférieur au :math:`n+1^{\text{ème}}` de la seconde liste +# +# Par conséquent, si *l* est la longueur de la liste la plus courte, +# comparer ces deux listes d'entiers revient à parcourir tous les indices +# depuis 0 jusqu'à *l* exclu et à s'arrêter sur la première différence qui +# détermine le résultat. S'il n'y pas de différence, alors la liste la +# plus courte est la première. Il faut écrire une fonction +# ``compare_liste(p,q)`` qui implémente cet algorithme. + + +def compare_liste(p, q): + i = 0 + while i < len(p) and i < len(q): + if p[i] < q[i]: + return -1 # on peut décider + elif p[i] > q[i]: + return 1 # on peut décider + i += 1 # on ne peut pas décider + # fin de la boucle, il faut décider à partir des longueurs des listes + if len(p) < len(q): + return -1 + elif len(p) > len(q): + return 1 + else: + return 0 + + +compare_liste([0, 1], [0, 1, 2]) + + +###################################### +# + +compare_liste([0, 1, 3], [0, 1, 2]) + + +###################################### +# + +compare_liste([0, 1, 2], [0, 1, 2]) + + +###################################### +# + +compare_liste([0, 1, 2, 4], [0, 1, 2]) + + +###################################### +# Q3 - précision des calculs +# ========================== +# +# On cherche à calculer la somme des termes d'une suite géométriques +# de raison :math:`\frac{1}{2}`. On définit :math:`r=\frac{1}{2}`, on cherche donc +# à calculer :math:`\sum_{i=0}^{\infty} r^i` qui une somme convergente mais infinie. +# Le programme suivant permet d'en calculer une valeur approchée. +# Il retourne, outre le résultat, le nombre d'itérations +# qui ont permis d'estimer le résultat. + + +def suite_geometrique_1(r): + x = 1.0 + y = 0.0 + n = 0 + while x > 0: + y += x + x *= r + n += 1 + return y, n + + +print(suite_geometrique_1(0.5)) + + +###################################### +# Un informaticien plus expérimenté a écrit le programme suivant qui +# retourne le même résultat mais avec un nombre d'itérations beaucoup plus petit. + + +def suite_geometrique_2(r): + x = 1.0 + y = 0.0 + n = 0 + yold = y + 1 + while abs(yold - y) > 0: + yold = y + y += x + x *= r + n += 1 + return y, n + + +print(suite_geometrique_2(0.5)) + + +###################################### +# Expliquez pourquoi le second programme est plus rapide tout en +# retournant le même résultat. Repère numérique : :math:`2^{-55} \sim 2,8.10^{-17}`. +# +# Tout d'abord le second programme est plus rapide car il effectue moins +# d'itérations, 55 au lieu de 1075. Maintenant, il s'agit de savoir pourquoi +# le second programme retourne le même résultat que le premier mais plus +# rapidement. L'ordinateur ne peut pas calculer numériquement une somme infinie, +# il s'agit toujours d'une valeur approchée. L'approximation dépend de la +# précision des calculs, environ 14 chiffres pour *python*. Dans le premier programme, +# on s'arrête lorsque :math:`r^n` devient nul, autrement dit, on +# s'arrête lorsque *x* est si petit que *python* ne peut plus le +# représenter autrement que par 0, +# c'est-à-dire qu'il n'est pas possible de représenter un nombre dans l'intervalle +# :math:`[0,2^{-1055}]`. +# +# Toutefois, il n'est pas indispensable d'aller aussi loin car +# l'ordinateur n'est de toute façon pas capable d'ajouter un nombre +# aussi petit à un nombre plus grand que 1. Par exemple, +# :math:`1 + 10^{17} = 1,000\, 000\, 000\, 000\, 000\, 01`. +# Comme la précision des calculs n'est que de 15 chiffres, +# pour *python*, :math:`1 + 10^{17} = 1`. +# Le second programme s'inspire de cette remarque : le calcul s'arrête +# lorsque le résultat de la somme n'évolue plus car il additionne des +# nombres trop petits à un nombre trop grand. L'idée est donc de comparer +# la somme d'une itération à l'autre et de s'arrêter lorsqu'elle n'évolue plus. +# +# Ce raisonnement n'est pas toujours applicable. Il est valide dans ce cas +# car la série :math:`s_n = \sum_{i=0}^{n} r^i` est croissante et positive. +# Il est valide pour une série convergente de la forme :math:`s_n = \sum_{i=0}^{n} u_i` +# et une suite $u_n$ de module décroissant. +# +# Q4 - hypercube +# ============== +# +# Un chercheur cherche à vérifier qu'une suite de 0 et de 1 est aléatoire. +# Pour cela, il souhaite compter le nombre de séquences de *n* nombres successifs. +# Par exemple, pour la suite 01100111 et :math:`n=3`, les triplets sont +# 011, 110, 100, 001, 011, 111. Le triplet 011 apparaît deux fois, +# les autres une fois. Si la suite est aléatoire, les occurrences de chaque +# triplet sont en nombres équivalents. + + +def hyper_cube_liste(n, m=None): + if m is None: + m = [0, 0] + if n > 1: + m[0] = [0, 0] + m[1] = [0, 0] + m[0] = hyper_cube_liste(n - 1, m[0]) + m[1] = hyper_cube_liste(n - 1, m[1]) + return m + + +hyper_cube_liste(3) + + +###################################### +# La seconde à base de dictionnaire (plus facile à manipuler) : + + +def hyper_cube_dico(n): + r = {} + ind = [0 for i in range(0, n)] + while ind[0] <= 1: + cle = tuple(ind) # conversion d'une liste en tuple + r[cle] = 0 + ind[-1] += 1 + k = len(ind) - 1 + while ind[k] == 2 and k > 0: + ind[k] = 0 + ind[k - 1] += 1 + k -= 1 + return r + + +hyper_cube_dico(3) + + +###################################### +# Le chercheur a commencé à écrire son programme : + + +def occurrence(li, n): + # d = ....... # choix d'un hyper_cube (n) + # ..... + # return d + pass + + +suite = [0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1] +h = occurrence(suite, 3) +h + + +###################################### +# Sur quelle structure se porte votre choix (a priori celle avec dictionnaire), +# compléter la fonction ``occurrence``. + + +def occurrence(tu, n): + d = hyper_cube_dico(n) + for i in range(0, len(tu) - n): + cle = tu[i : i + n] + d[cle] += 1 + return d + + +occurrence((1, 0, 1, 1, 0, 1, 0), 3) + + +###################################### +# Il est même possible de se passer de la fonction ``hyper_cube_dico`` : + + +def occurrence2(tu, n): + d = {} + for i in range(0, len(tu) - n): + cle = tu[i : i + n] + if cle not in d: + d[cle] = 0 + d[cle] += 1 + return d + + +occurrence2((1, 0, 1, 1, 0, 1, 0), 3) + + +###################################### +# La seule différence apparaît lorsqu'un n-uplet n'apparaît pas dans +# la liste. Avec la fonction ``hyper_cube_dico``, ce n-uplet recevra la +# fréquence 0, sans cette fonction, ce n-uplet ne sera pas présent +# dans le dictionnaire ``d``. Le même programme avec la structure matricielle +# est plus une curiosité qu'un cas utile. + + +def occurrence3(li, n): + d = hyper_cube_liste(n) + for i in range(0, len(li) - n): + cle = li[i : i + n] + t = d # + for k in range(0, n - 1): # point clé de la fonction : + t = t[cle[k]] # accès à un élément + t[cle[n - 1]] += 1 + return d + + +occurrence3((1, 0, 1, 1, 0, 1, 0), 3) + + +###################################### +# Une autre écriture... + + +def hyper_cube_liste2(n, m=[0, 0], m2=[0, 0]): + if n > 1: + m[0] = list(m2) + m[1] = list(m2) + m[0] = hyper_cube_liste2(n - 1, m[0]) + m[1] = hyper_cube_liste2(n - 1, m[1]) + return m + + +def occurrence4(li, n): + d = hyper_cube_liste2(n) # * remarque voir plus bas + for i in range(0, len(li) - n): + cle = li[i : i + n] + t = d # + for k in range(0, n - 1): # point clé de la fonction : + t = t[cle[k]] # accès à un élément + t[cle[n - 1]] += 1 + return d + + +occurrence4((1, 0, 1, 1, 0, 1, 0), 3) + + +###################################### +# Et si on remplace ``list(m2)`` par ``m2``. + + +def hyper_cube_liste3(n, m=[0, 0], m2=[0, 0]): + if n > 1: + m[0] = m2 + m[1] = m2 + m[0] = hyper_cube_liste3(n - 1, m[0]) + m[1] = hyper_cube_liste3(n - 1, m[1]) + return m + + +def occurrence5(li, n): + d = hyper_cube_liste3(n) # * remarque voir plus bas + for i in range(0, len(li) - n): + cle = li[i : i + n] + t = d # + for k in range(0, n - 1): # point clé de la fonction : + t = t[cle[k]] # accès à un élément + t[cle[n - 1]] += 1 + return d + + +try: + occurrence5((1, 0, 1, 1, 0, 1, 0), 3) +except Exception as e: + print(e) + + +###################################### +# Intéressant... diff --git a/_doc/examples/lambda_function.py b/_doc/examples/plot_lambda_function.py similarity index 98% rename from _doc/examples/lambda_function.py rename to _doc/examples/plot_lambda_function.py index 74114529..5f53deb8 100644 --- a/_doc/examples/lambda_function.py +++ b/_doc/examples/plot_lambda_function.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 """ Astuces avec les lambda functions ================================= diff --git a/_doc/examples/plot_numpy_tricks.py b/_doc/examples/plot_numpy_tricks.py new file mode 100644 index 00000000..3c732436 --- /dev/null +++ b/_doc/examples/plot_numpy_tricks.py @@ -0,0 +1,48 @@ +# coding: utf-8 +""" +================================== +Points d'implémentation avec numpy +================================== + +Quelques écritures efficaces et non efficaces avec :epkg:`numpy`. + +accéder à un élément en particulier +=================================== +""" +import timeit + +import numpy + +mat = numpy.zeros((5, 5)) +for i in range(mat.shape[0]): + for j in range(mat.shape[1]): + mat[i, j] = i * 10 + j +mat + + +######################################## +# + + +mat[2, 3], mat[2][3] + + +######################################## +# + +timeit.timeit("mat[2, 3]", globals=globals(), number=100) + + +######################################## +# + +timeit.timeit("mat[2][3]", globals=globals(), number=100) + + +######################################## +# Les deux écritures ont l'air identique puisqu'elle retourne le même résultat. +# Néanmoins, ``mat[2][3]`` crée un tableau temporaire puis extrait un élément. +# Les éléments ne sont pas recopiés mais un objet intermédiaire est créé. + + +mat[2] diff --git a/_doc/examples/plot_pandas_groupby.py b/_doc/examples/plot_pandas_groupby.py new file mode 100644 index 00000000..44da9176 --- /dev/null +++ b/_doc/examples/plot_pandas_groupby.py @@ -0,0 +1,35 @@ +# coding: utf-8 +""" +================= +Pandas et groupby +================= + +Petit tour de passe passe autour d'un :meth:`pandas.DataFrame.groupby` +et des valeurs manquantes qui ne sont plus prises en compte +depuis les dernières versions. + +groupby et valeur manquantes +============================ +""" + + +import pandas + + +data = [{"a": 1, "b": 2}, {"a": 10, "b": 20}, {"b": 3}, {"b": 4}] +df = pandas.DataFrame(data) +df + + +######################################## +# + +df.groupby("a").sum() + + +######################################## +# Les valeurs manquantes ont disparu et c'est le comportement attendu +# Il est possible de corriger le tir avec l'argument `dropna`. + + +df.groupby("a", dropna=False).sum() diff --git a/_doc/examples/plot_partie_dame.py b/_doc/examples/plot_partie_dame.py new file mode 100644 index 00000000..aca73568 --- /dev/null +++ b/_doc/examples/plot_partie_dame.py @@ -0,0 +1,266 @@ +# coding: utf-8 +""" + +.. _partiedamerst: + +================ +Parties de dames +================ + +Exercice de programmation sur les tableaux. + +Q1 +== + +Une partie de dames met en jeu quarante pions, vingt noirs, vingt blancs, +chacun sur des cases différentes. L'objectif est de savoir si un pion est +en mesure d'en prendre un autre. On ne traitera pas le cas des dames. +Chaque pion est défini par : + +* deux coordonnées entières, chacune comprise entre 1 et 10 +* une couleur, noir ou blanc + +On propose deux représentations de l'ensemble de pions : + +* Un tableau de 40 pions indicés de 0 à 39 inclus, chaque pion étant défini par : + * deux coordonnées comprises entre 1 et 10, ou (0,0) + si le pion n'est plus sur le damier + * un entier qui vaut 1 pour blanc, 2 pour noir +* Un tableau d'entiers à deux dimensions, chaque case contient : + * soit 0 s'il n'y a pas de pion + * soit 1 si la case contient un pion blanc + * soit 2 si la case contient un pion noir + +Y a-t-il d'autres représentations de ces informations ? Si on considère +que l'efficacité d'une méthode est reliée à sa vitesse - autrement dit aux +coûts des algorithmes qu'elles utilisent -, parmi ces deux représentations, +quelle est celle qui semble la plus efficace pour savoir si un pion donné +du damier est en mesure d'en prendre un autre ? + +**réponse** + +La seconde représentation sous forme de tableau à deux dimensions est +plus pratique pour effectuer les tests de voisinages. Chaque case a +quatre voisines aux quatre coins, il est ensuite facile de déterminer +si ces quatre voisines sont libres ou si elles contiennent un pion. +On sait rapidement le contenu d'une case. + +Avec la première représentation - le tableau des pions - pour savoir +s'il existe un pion dans une case voisine, il faut passer en revue +tous les pions pour savoir si l'un d'eux occupe ou non cette case. +Avec la seconde représentation - le tableau à deux dimensions - +on accède directement à cette information sans avoir à la rechercher. +On évite une boucle sur les pions avec la seconde représentation. + +Q2 +== + +Comment représenter un tableau d'entiers à deux dimensions en +langage python à l'aide des types standards qu'il propose, +à savoir t-uple, liste ou dictionnaire ? + +**réponse** + +Pour représenter le tableau en deux dimensions, il existe trois solutions : + +* Une liste de listes, chaque ligne est représentée par une liste. + Toutes ces listes sont elles-mêmes assemblées dans une liste globale. +* Une seule liste, il suffit de numéroter les cases du damier de 0 à 99, + en utilisant comme indice pour la case :math:`(i,j)` : :math:`k = 10*i+j`. + Réciproquement, la case d'indice $k$ aura pour coordonnées + :math:`(k / 10, \, k \% 10)`. +* Un dictionnaire dont la clé est un couple d'entiers. + +Q3 +== + +On cherche à écrire l'algorithme qui permet de savoir si un pion donné +est un mesure de prendre un pion. Quels sont les paramètres +d'entrées et les résultats de cet algorithme ? + +**réponse** + +On désire savoir si le pion de la case :math:`(i,j)` +peut en prendre un autre. On suppose que le tableau à deux dimensions +est une liste de dix listes appelée ``damier``. ``damier[i][j]`` +est donc la couleur du pion de la case :math:`(i,j)`, +à savoir 0 si la case est vide, 1 si le pion est blanc, 2 si le pion est noir. +Pour ces deux derniers cas, la couleur des pions de l'adversaire sera donc +``3 - damier[i][j]``. Les entrées de la fonctions sont donc les indices +``i``, ``j`` et le damier ``damier``. La sortie est une variable booléenne qui +indique la possibilité ou non de prendre. On ne souhaite pas déplacer les pions. + +Q4 +== + +Il ne reste plus qu'à écrire cet algorithme. +""" + + +def pion_prendre(i, j, damier): + c = damier[i][j] + if c == 0: + return False # case vide, impossible de prendre + c = 3 - c # couleur de l'adversaire + + if damier[i - 1][j - 1] == c: # s'il y a un pion adverse en haut à gauche + if damier[i - 2][j - 2] == 0: # si la case d'après en diagonale est vide + return True # on peut prendre + + # on répète ce test pour les trois autres cases + if damier[i - 1][j + 1] == c and damier[i - 2][j + 2] == 0: + return True + if damier[i + 1][j - 1] == c and damier[i + 2][j - 2] == 0: + return True + if damier[i + 1][j + 1] == c and damier[i + 2][j + 2] == 0: + return True + + # si tous les tests ont échoué, on ne peut pas prendre + return False + + +damier = [ + [0, 0, 1, 0, 0], + [0, 1, 0, 1, 0], + [0, 0, 2, 0, 2], + [0, 0, 0, 2, 0], + [0, 0, 0, 0, 0], +] + +pion_prendre(2, 2, damier) + + +######################################## +# Voici une fonction équivalente lorsque le damier est un dictionnaire +# dont la clé est un couple d'entiers. + + +def pion_prendre_dict(i, j, damier): + c = damier[(i, j)] # ou encore damier [i,j] + if c == 0: + return False # case vide, impossible de prendre + c = 3 - c # couleur de l'adversaire + + # test pour une prise du pion dans les quatre cases voisines + if damier[i - 1, j - 1] == c and damier[i - 2, j - 2] == 0: + return True + if damier[i - 1, j + 1] == c and damier[i - 2, j + 2] == 0: + return True + if damier[i + 1, j - 1] == c and damier[i + 2, j - 2] == 0: + return True + if damier[i + 1, j + 1] == c and damier[i + 2, j + 2] == 0: + return True + + # si tous les tests ont échoué, on ne peut pas prendre + return False + + +damier_dict = {(i, j): damier[i][j] for i in range(4) for j in range(4)} + +print(damier_dict) + +pion_prendre_dict(2, 2, damier_dict) + + +######################################### +# + +try: + pion_prendre_dict(1, 3, damier_dict) +except Exception as e: + print(e) + + +############################################## +# Cela ne marche pas très bien, cela laisse supposer que la fonction +# précédente n'est pas très fonctionnelle non plus. Il manque le fait de +# vérifier que les coordonnées testées restent dans l'échiquier. +# La même fonction lorsque le damier est représenté par une seule liste. + + +def pion_prendre_list(i, j, damier): + n = int(len(damier) ** 0.5) # on suppose que le damier est carré + c = damier[n * i + j] + if c == 0: + return False # case vide, impossible de prendre + c = 3 - c # couleur de l'adversaire + + # test pour une prise du pion dans les quatre cases voisines + if damier[n * (i - 1) + j - 1] == c and damier[n * (i - 2) + j - 2] == 0: + return True + if damier[n * (i - 1) + j + 1] == c and damier[n * (i - 2) + j + 2] == 0: + return True + if damier[n * (i + 1) + j - 1] == c and damier[n * (i + 2) + j - 2] == 0: + return True + if damier[n * (i + 1) + j + 1] == c and damier[n * (i + 2) + j + 2] == 0: + return True + + return False + + +damier_list = [] +for row in damier: + damier_list.extend(row) + +print(damier_list) + +pion_prendre_list(2, 2, damier_list) + +########################################### +# Pour ces trois cas, aucun effet de bord n'a été envisagé. +# Si la case est trop près d'un des bords, un des indices +# :math:`i,\;j,\;i-1,\;j-1,\;i+1,\;j+1,\;i-2,\;j-2,\;i+2,\;j+2` +# désignera une case hors du damier. Le code de la fonction +# ``pion_prendre`` devra donc vérifier que chaque case dont elle +# vérifie le contenu appartient au damier. + + +def pion_prendre_bord(i, j, damier): + c = damier[i][j] + if c == 0: + return False # case vide, impossible de prendre + c = 3 - c # couleur de l'adversaire + + # on répète ce test pour les trois autres cases + if i >= 2 and j >= 2 and damier[i - 1][j - 1] == c and damier[i - 2][j - 2] == 0: + return True + if ( + i >= 2 + and j < len(damier) - 2 + and damier[i - 1][j + 1] == c + and damier[i - 2][j + 2] == 0 + ): + return True + + if ( + i < len(damier) - 2 + and j >= 2 + and damier[i + 1][j - 1] == c + and damier[i + 2][j - 2] == 0 + ): + return True + + if ( + i < len(damier) - 2 + and j < len(damier) - 2 + and damier[i + 1][j + 1] == c + and damier[i + 2][j + 2] == 0 + ): + return True + + return False + + +pion_prendre_bord(2, 2, damier) + + +######################################### +# + +pion_prendre_bord(1, 3, damier) + + +######################################### +# La fonction ``pion_prendre(1, 3, damier)`` fonctionne parce que le +# langage python accepte indices négatifs : ``damier[-1][-1]`` +# mais le résultat n'est pas nécessairement celui souhaité. diff --git a/_doc/examples/plot_serialisation_examples.py b/_doc/examples/plot_serialisation_examples.py new file mode 100644 index 00000000..e6bb21f9 --- /dev/null +++ b/_doc/examples/plot_serialisation_examples.py @@ -0,0 +1,523 @@ +# coding: utf-8 +""" +============= +Sérialisation +============= + +Le notebook explore différentes façons de sérialiser des données et leurs limites. + +JSON +==== + +Le format :epkg:`JSON` est le format le plus utilisé sur internet +notemmant via les :epkg:`API REST`. + +Ecriture (json) ++++++++++++++++ +""" +from io import StringIO, BytesIO +import timeit +import json +import numpy +import ujson +import cloudpickle +import pickle + + +data = { + "records": [ + { + "nom": "Xavier", + "prénom": "Xavier", + "langages": [{"nom": "C++", "age": 40}, {"nom": "Python", "age": 20}], + } + ] +} + + +######################################### +# + +buffer = StringIO() +res = json.dump(data, buffer) # 1 +seq = buffer.getvalue() +seq + + +######################################### +# Lecture (json) +# ++++++++++++++ + + +buffer = StringIO(seq) +read = json.load(buffer) +read + + +######################################### +# Limite +# ++++++ +# +# Les matrices :epkg:`numpy` ne sont pas sérialisables facilement. + + +data = {"mat": numpy.array([0, 1])} + +buffer = StringIO() +try: + json.dump(data, buffer) +except Exception as e: + print(e) + + +######################################### +# Les classes ne sont pas sérialisables non plus facilement. + + +class A: + def __init__(self, att): + self.att = att + + +data = A("e") +buffer = StringIO() +try: + json.dump(data, buffer) +except Exception as e: + print(e) + + +######################################### +# Pour ce faire, il faut indiquer au module :mod:`json` +# comment convertir la classe en un ensemble de listes et dictionnaires et +# la classe :class:`json.JSONEncoder`. + + +class MyEncoder(json.JSONEncoder): + def default(self, o): + return {"classname": o.__class__.__name__, "data": o.__dict__} + + +data = A("e") +buffer = StringIO() +res = json.dump(data, buffer, cls=MyEncoder) +res = buffer.getvalue() +res + +######################################### +# Et la relecture avec la classe :class:`json.JSONDecoder`. + + +class MyDecoder(json.JSONDecoder): + def decode(self, o): + dec = json.JSONDecoder.decode(self, o) + if isinstance(dec, dict) and dec.get("classname") == "A": + return A(dec["data"]["att"]) + else: + return dec + + +buffer = StringIO(res) +obj = json.load(buffer, cls=MyDecoder) +obj + + +######################################### +# Sérialisation rapide +# ++++++++++++++++++++ +# +# Le module :mod:`json` est la librairie standard de Python mais comme +# la sérialisation au format *JSON* est un besoin très fréquent, +# il existe des alternative plus rapide comme :epkg:`ujson`. + + +data = { + "records": [ + { + "nom": "Xavier", + "prénom": "Xavier", + "langages": [{"nom": "C++", "age": 40}, {"nom": "Python", "age": 20}], + } + ] +} + + +######################################### +# + + +timeit.timeit("json.dump(data, StringIO())", globals=globals(), number=100) + + +######################################### +# + + +timeit.timeit("ujson.dump(data, StringIO())", globals=globals(), number=100) + + +######################################### +# Ces deux lignes mesures l'écriture au format JSON +# mais il faut aussi mesurer la lecture. + + +buffer = StringIO() +ujson.dump(data, buffer) +res = buffer.getvalue() +timeit.timeit("json.load(StringIO(res))", globals=globals(), number=100) + + +######################################### +# + +timeit.timeit("ujson.load(StringIO(res))", globals=globals(), number=100) + + +######################################### +# On enlève le temps passé dans la creation du buffer. + + +timeit.timeit("StringIO(res)", globals=globals(), number=100) + + +######################################### +# Pickle +# ====== +# +# Le module :mod:`pickle` effectue la même chose mais au format binaire. +# Celui-ci est propre à *Python* et ne peut être lu d'autres langages, +# voire parfois par d'autres versions de *Python*. +# +# Ecriture (pickle) +# +++++++++++++++++ + + +data = { + "records": [ + { + "nom": "Xavier", + "prénom": "Xavier", + "langages": [{"nom": "C++", "age": 40}, {"nom": "Python", "age": 20}], + } + ] +} + + +######################################### +# + + +buffer = BytesIO() +res = pickle.dump(data, buffer) +seq = buffer.getvalue() +seq + + +######################################### +# Lecture (pickle) +# ++++++++++++++++ + + +buffer = BytesIO(seq) +read = pickle.load(buffer) +read + + +######################################### +# Les classes +# +++++++++++ +# +# A l'inverse du format *JSON*, les classes sont sérialisables avec +# :mod:`pickle` parce que le langage utilise un format très proche +# de ce qu'il a en mémoire. Il n'a pas besoin de conversion supplémentaire. + + +data = A("r") +buffer = BytesIO() +res = pickle.dump(data, buffer) +seq = buffer.getvalue() +seq + + +######################################### +# + +buffer = BytesIO(seq) +read = pickle.load(buffer) +read + + +######################################### +# Réduire la taille +# +++++++++++++++++ +# +# Certaines informations sont duppliquées et il est préférable de ne pas +# les sérialiser deux fois surtout si elles sont voluminueuses. + + +class B: + def __init__(self, att): + self.att1 = att + self.att2 = att + + +######################################### +# + +data = B("r") +buffer = BytesIO() +res = pickle.dump(data, buffer) +seq = buffer.getvalue() +seq + + +######################################### +# Evitons maintenant de stocker deux fois le même attribut. + + +class B: + def __init__(self, att): + self.att1 = att + self.att2 = att + + def __getstate__(self): + return dict(att=self.att1) + + +data = B("r") +buffer = BytesIO() +res = pickle.dump(data, buffer) +seq = buffer.getvalue() +seq + + +######################################### +# C'est plus court mais il faut inclure maintenant la relecture. + + +class B: + def __init__(self, att): + self.att1 = att + self.att2 = att + + def __getstate__(self): + return dict(att=self.att1) + + def __setstate__(self, state): + setattr(self, "att1", state["att"]) + setattr(self, "att2", state["att"]) + + +buffer = BytesIO(seq) +read = pickle.load(buffer) +read + + +######################################### +# + +read.att1, read.att2 + + +######################################### +# + +data = B("r") +timeit.timeit("pickle.dump(data, BytesIO())", globals=globals(), number=100) + + +######################################### +# + +timeit.timeit("pickle.load(BytesIO(seq))", globals=globals(), number=100) + + +######################################### +# La sérialisation binaire est habituellement plus rapide dans les langages +# bas niveau comme C++. La même comparaison pour un langage haut niveau +# tel que Python n'est pas toujours prévisible. +# Il est possible d'accélérer un peu les choses. + + +timeit.timeit( + "pickle.dump(data, BytesIO(), protocol=pickle.HIGHEST_PROTOCOL)", + globals=globals(), + number=100, +) + + +######################################### +# Cas des fonctions +# ================= +# +# La sérialisation s'applique à des données et non à du code mais le +# fait de sérialiser des fonctions est tout de même tentant. +# La sérialisation binaire fonctionne même avec les fonctions. +# +# Binaire +# +++++++ + + +def myfunc(x): + return x + 1 + + +data = {"x": 5, "f": myfunc} + + +buffer = BytesIO() +res = pickle.dump(data, buffer) +buffer.getvalue() + + +######################################### +# + + +res = pickle.load(BytesIO(buffer.getvalue())) +res + + +######################################### +# + +res["f"](res["x"]) + + +######################################### +# La sérialisation ne conserve pas le code de la fonction, juste son nom. +# Cela veut dire que si elle n'est pas disponible lorsqu'elle est appelée, +# il sera impossible de s'en servir. + + +del myfunc + + +try: + pickle.load(BytesIO(buffer.getvalue())) +except Exception as e: + print(e) + + +######################################### +# Il est possible de contourner l'obstacle en utilisant le module +# :epkg:`cloudpickle` qui stocke le code de la fonction. + + +def myfunc(x): + return x + 1 + + +data = {"x": 5, "f": myfunc} + + +buffer = BytesIO() +res = cloudpickle.dump(data, buffer) +buffer.getvalue() + + +######################################### +# + +del myfunc + + +res = cloudpickle.load(BytesIO(buffer.getvalue())) +res + + +######################################### +# + +res["f"](res["x"]) + + +######################################### +# Fonction et JSON +# ++++++++++++++++ +# +# La sérialisation d'une fonction au format JSON ne +# fonctionne pas avec le module standard. + + +buffer = StringIO() +try: + json.dump(data, buffer) # 2 +except Exception as e: + print(e) + + +######################################### +# La sérialisation avec :epkg:`ujson` ne fonctionne pas non plus +# même si elle ne produit pas toujours d'erreur. + + +buffer = StringIO() +try: + res = ujson.dump(data, buffer) # 3 +except TypeError as e: + print(e) +buffer.getvalue() + + +######################################### +# Cas des itérateurs +# ================== +# +# Les itérateurs fonctionnent avec la sérialisation binaire mais ceci +# implique de stocker l'ensemble que l'itérateur parcourt. + + +ens = [1, 2] + +data = {"x": 5, "it": iter(ens)} + + +buffer = BytesIO() +res = pickle.dump(data, buffer) # 4 +buffer.getvalue() + + +######################################### +# + +del ens + +res = pickle.load(BytesIO(buffer.getvalue())) +res + + +######################################### +# + +list(res["it"]) + + +######################################### +# + +list(res["it"]) + + +######################################### +# Cas des générateurs +# =================== +# +# Ils ne peuvent être sérialisés car le langage n'a pas accès à l'ensemble +# des éléments que le générateur parcourt. Il n'y a aucun moyen de +# sérialiser un générateur mais on peut sérialiser la fonction qui crée le générateur. + + +def ensgen(): + yield 1 + yield 2 + + +data = {"x": 5, "it": ensgen()} + + +buffer = BytesIO() +try: + pickle.dump(data, buffer) +except Exception as e: + print(e) diff --git a/_doc/examples/plot_serialisation_protobuf.py b/_doc/examples/plot_serialisation_protobuf.py new file mode 100644 index 00000000..5ca04343 --- /dev/null +++ b/_doc/examples/plot_serialisation_protobuf.py @@ -0,0 +1,275 @@ +# coding: utf-8 +""" +.. _l-example-protobuf: + +=========================== +Sérialisation avec protobuf +=========================== + +:epkg:`protobuf` optimise la sérialisation de deux façons. +Elle accélère l'écriture et la lecture des données et permet aussi +un accès rapide à une information précise dans désérialiser +les autres. Elle réalise cela en imposant un schéma strict de données. + +L'exemple fonctionne si l'exécutable `protoc` et le package `protobuf` +ont des versions compatibles. Un message apparaîtra dans le cas contraire. + +:: + + protoc --version + python -c "import google.protobuf as gp;print(gp.__version__)" + +Schéma +====== + +On récupère l'exemple du `tutorial +`_. +""" +import os +import sys +import timeit +import struct +from io import BytesIO +from sphinx_runpython.runpython import run_cmd +import google.protobuf as gp +from google.protobuf.json_format import MessageToJson, Parse as ParseJson + +schema = """ +syntax = "proto2"; + +package tutorial; + +message Person { + optional string name = 1; + optional int32 id = 2; + optional string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + optional string number = 1; + optional PhoneType type = 2 [default = HOME]; + } + + repeated PhoneNumber phones = 4; +} + +message AddressBook { + repeated Person people = 1; +} +""" + +###################################### +# Compilation +# =========== +# +# Il faut d'abord récupérer le compilateur. Cela peut se faire depuis +# le site de :epkg:`protobuf` ou sur Linux (Ubuntu/Debian) +# ``apt-get install protobuf-compiler`` pour obtenir le programme ``protoc``. + + +version = gp.__version__ +version + + +######################################### +# + + +with open("schema.proto", "w") as f: + f.write(schema) + + +# Et on peut compiler. + +# In[8]: + + +cmd = "protoc --python_out=. schema.proto" +out, err = run_cmd(cmd=cmd, wait=True) +print(out) +print(err) + + +######################################## +# Un fichier a été généré. + + +[_ for _ in os.listdir(".") if ".py" in _] + + +######################################## + + +with open("schema_pb2.py", "r") as f: + content = f.read() +print(content[:1000]) + + +######################################## +# Import du module créé +# ===================== +# +# Pour utliser *protobuf*, il faut importer le module créé. + + +sys.path.append(".") +import schema_pb2 # noqa: E402 + +######################################## +# On créé un enregistrement. + + +person = schema_pb2.Person() +person.id = 1234 +person.name = "John Doe" +person.email = "jdoe@example.com" +phone = person.phones.add() +phone.number = "555-4321" +phone.type = schema_pb2.Person.HOME + + +######################################## +# + +person + + +######################################## +# Sérialisation en chaîne de caractères +# ===================================== + + +res = person.SerializeToString() +type(res), res + + +######################################## +# + +timeit.timeit("person.SerializeToString()", globals=globals(), number=100) + + +######################################## +# + +pers = schema_pb2.Person.FromString(res) +pers + + +######################################## +# + +pers = schema_pb2.Person() +pers.ParseFromString(res) +pers + + +######################################## +# + +timeit.timeit("schema_pb2.Person.FromString(res)", globals=globals(), number=100) + + +######################################## +# + +timeit.timeit("pers.ParseFromString(res)", globals=globals(), number=100) + + +######################################## +# Plusieurs chaînes de caractères +# =============================== + + +db = [] + +person = schema_pb2.Person() +person.id = 1234 +person.name = "John Doe" +person.email = "jdoe@example.com" +phone = person.phones.add() +phone.number = "555-4321" +phone.type = schema_pb2.Person.HOME +db.append(person) + +person = schema_pb2.Person() +person.id = 5678 +person.name = "Johnette Doette" +person.email = "jtdoet@example2.com" +phone = person.phones.add() +phone.number = "777-1234" +phone.type = schema_pb2.Person.MOBILE +db.append(person) + + +######################################## +# + + +buffer = BytesIO() +for p in db: + size = p.ByteSize() + buffer.write(struct.pack("i", size)) + buffer.write(p.SerializeToString()) +res = buffer.getvalue() +res + + +######################################## +# + + +db2 = [] +buffer = BytesIO(res) +n = 0 +while True: + bsize = buffer.read(4) + if len(bsize) == 0: + # C'est fini. + break + size = struct.unpack("i", bsize)[0] + data = buffer.read(size) + p = schema_pb2.Person.FromString(data) + db2.append(p) + + +######################################## +# + +db2[0], db2[1] + + +######################################## +# Sérialisation JSON +# ================== + + +print(MessageToJson(pers)) + + +######################################## +# + +timeit.timeit("MessageToJson(pers)", globals=globals(), number=100) + + +######################################## +# + + +js = MessageToJson(pers) +res = ParseJson(js, message=schema_pb2.Person()) +res + + +######################################## +# + +timeit.timeit( + "ParseJson(js, message=schema_pb2.Person())", globals=globals(), number=100 +) diff --git a/_doc/examples/plot_tarabiscote.py b/_doc/examples/plot_tarabiscote.py new file mode 100644 index 00000000..f7bce5dc --- /dev/null +++ b/_doc/examples/plot_tarabiscote.py @@ -0,0 +1,456 @@ +# coding: utf-8 +""" + +.. _tarabiscoterst: + +==================================== +Exercices expliqués de programmation +==================================== + +Quelques exercices autour de la copie de liste, du temps de calcul, de l'héritage. + +Copie de listes +=============== + +La fonction ``somme`` est censée faire la concaténation de toutes les +listes contenues dans ``ens``. Le résultat retourné est effectivement +celui désiré mais la fonction modifie également la liste ``ens``, pourquoi ? +""" +import math +import copy +import numpy + + +def somme(tab): + li = tab[0] + for i in range(1, len(tab)): + li += tab[i] + return li + + +ens = [[0, 1], [2, 3]] +print(somme(ens)) +print(ens) + + +######################################## +# Le problème vient du fait qu'une affectation en *python* +# (seconde ligne de la fonction ``somme`` ne fait pas une copie +# mais crée un second identificateur pour désigner la même chose. +# Ici, ``l`` et ``tab[0]`` désignent la même liste, modifier l'une +# modifie l'autre. Ceci explique le résultat. Pour corriger, +# il fallait faire une copie explicite de ``tab[0]`` : + + +def somme(tab): + li = copy.copy(tab[0]) ###### ligne modifiée + for i in range(1, len(tab)): + li += tab[i] + return li + + +ens = [[0, 1], [2, 3]] +print(somme(ens)) +print(ens) + + +######################################## +# Il était possible, dans ce cas, de se passer de copie en écrivant : + + +def somme(tab): + li = [] ###### ligne modifiée + for i in range(0, len(tab)): ###### ligne modifiée + li += tab[i] + return li + + +ens = [[0, 1], [2, 3]] +print(somme(ens)) +print(ens) + + +######################################## +# Erreur de logique +# ================= +# +# Le programme suivant fonctionne mais le résultat n'est pas celui escompté. + + +li = ["un", "deux", "trois", "quatre", "cinq"] + +for i in range(0, len(li)): + mi = i + for j in range(i, len(li)): + if li[mi] < li[j]: + mi = j + e = li[i] + li[mi] = li[i] + li[i] = e + +li + + +######################################## +# Ce programme est censé effectuer un tri par ordre alphabétique +# **décroissant**. Le problème intervient lors de la permutation de +# l'élément ``l[i]`` avec l'élément ``l[mi]``. Il faut donc écrire : + + +li = ["un", "deux", "trois", "quatre", "cinq"] +for i in range(0, len(li)): + mi = i + for j in range(i, len(li)): + if li[mi] < li[j]: + mi = j + e = li[mi] ######## ligne modifiée + li[mi] = li[i] + li[i] = e + +li + + +######################################## +# Coût d'un algorithme +# ==================== +# +# Le coût d'un algorithme ou d'un programme est le nombre d'opérations +# (additions, multiplications, tests, ...) qu'il effectue. Il s'exprime +# comme un multiple d'une fonction de la dimension des données que +# le programme manipule. Par exemple : :math:`O(n)`, +# :math:`O(n^2)`, :math:`O(n\ln n)`, ... + + +def moyenne(tab): + s = 0.0 + for x in tab: + s += x + return s / len(tab) + + +def variance(tab): + s = 0.0 + for x in tab: + t = x - moyenne(tab) + s += t * t + return s / len(tab) + + +li = [0, 1, 2, 2, 3, 1, 3, 0] +print(moyenne(li)) +print(variance(li)) + + +######################################## +# Tout d'abord, le coût d'un algorithme est très souvent exprimé comme un +# multiple de la dimension des données qu'il traite. Ici, la dimension +# est la taille du tableau ``tab``. Par exemple, si on note ``n = len(tab)``, +# alors le coût de la fonction ``moyenne`` s'écrit :math:`O(n)` car cette +# fonction fait la somme des *n* éléments du tableau. +# +# La fonction ``variance`` contient quant à elle un petit piège. Si elle +# contient elle aussi une boucle, chacun des $n$ passages dans cette boucle +# fait appel à la fonction ``moyenne``. Le coût de la fonction ``variance`` est donc +# :math:`O(n^2)`. +# +# Il est possible d'accélérer le programme car la fonction ``moyenne`` +# retourne le même résultat à chaque passage dans la boucle. +# Il suffit de mémoriser son résultat dans une variable avant d'entrer +# dans la boucle comme suit : + + +def variance(tab): + s = 0.0 + m = moyenne(tab) + for x in tab: + t = x - m + s += t * t + return s / len(tab) + + +variance(li) + + +######################################## +# Le coût de la fonction ``variance`` est alors :math:`O(n)`. +# +# Le coût d'un algorithme peut être évalué de manière plus précise et +# nécessiter un résultat comme $n^2 + 3n + 2$ mais cette exigence est +# rarement utile pour des langages comme *python*. L'expression +# ``for x in tab:`` cache nécessairement un test qu'il faudrait prendre en +# compte si plus de précision était exigée. Il faudrait également se +# tourner vers un autre langage de programmation, plus précis dans sa syntaxe. +# Par exemple, lorsqu'on conçoit un programme avec le langage C ou C++, +# à partir du même code informatique, on peut construire deux programmes +# exécutables. Le premier (ou version *debug*), lent, sert à la mise au point : +# il inclut des tests supplémentaires permettant de vérifier à chaque étape +# qu'il n'y a pas eu d'erreur (une division par zéro par exemple). +# Lorsqu'on est sûr que le programme marche, on construit la seconde version +# (ou *release*), plus rapide, dont ont été ôtés tous ces tests de +# conception devenus inutiles. +# +# *python* aboutit à un programme lent qui inclut une quantité de tests +# invisibles pour celui qui programme mais qui détecte les erreurs plus vite +# et favorise une conception rapide. Il n'est pas adapté au traitement +# d'information en grand nombre et fait une multitude d'opérations cachées. +# +# Héritage double +# =============== +# +# On a besoin dans un programme de créer une classe ``carre`` et une classe +# ``rectangle``. Mais on ne sait pas quelle classe doit hériter de l'autre. +# Dans le premier programme, ``rectangle`` hérite de ``carre``. + + +class carre: + def __init__(self, a): + self.a = a + + def surface(self): + return self.a**2 + + +class rectangle(carre): + def __init__(self, a, b): + carre.__init__(self, a) + self.b = b + + def surface(self): + return self.a * self.b + + +rectangle(3, 4).surface() + + +######################################## +# Dans le second programme, c'est la classe ``carre`` +# qui hérite de la classe ``rectangle``. + + +class rectangle: + def __init__(self, a, b): + self.a = a + self.b = b + + def surface(self): + return self.a * self.b + + +class carre(rectangle): + def __init__(self, a): + rectangle.__init__(self, a, a) + + def surface(self): + return self.a**2 + + +carre(3).surface() + + +######################################## +# * Dans le second programme, est-il nécessaire de redéfinir +# la méthode ``surface`` dans la classe ``carre`` ? +# * Quel est le sens d'héritage qui vous paraît le plus censé, +# ``class rectangle(carre)`` ou ``class carre(rectangle)`` ? +# * On désire ajouter la classe ``losange``. Est-il plus simple que +# ``rectangle`` hérite de la classe ``carre`` ou l'inverse pour introduire +# la classe ``losange`` ? Quel ou quels attributs supplémentaires +# faut-il introduire dans la classe ``losange`` ? + +# Le principe de l'héritage est qu'une classe ``carre`` héritant de la classe +# ``rectangle`` hérite de ses attributs et méthodes. L'aire d'un carré est +# égale à celle d'un rectangle dont les côtés sont égaux, par conséquent, +# la méthode ``surface`` de la classe retourne la même valeur que celle de +# la classe ``rectangle``. Il n'est donc pas nécessaire de la redéfinir. +# +# * D'après la réponse de la première question, il paraît plus logique de +# considérer que ``carre`` hérite de ``rectangle``. +# * Un losange est défini par un côté et un angle ou un côté et la longueur +# d'une de ses diagonales, soit dans les deux cas, deux paramètres. +# Dans la première question, il paraissait plus logique que la classe +# la plus spécifique hérite de la classe la plus générale afin de bénéficier +# de ses méthodes. Pour introduire le losange, il paraît plus logique de +# partir du plus spécifique pour aller au plus général afin que chaque +# classe ne contienne que les informations qui lui sont nécessaires. + + +class carre: + def __init__(self, a): + self.a = a + + def surface(self): + return self.a**2 + + +class rectangle(carre): + def __init__(self, a, b): + carre.__init__(self, a) + self.b = b + + def surface(self): + return self.a * self.b + + +class losange(carre): + def __init__(self, a, theta): + carre.__init__(self, a) + self.theta = theta + + def surface(self): + return self.a * math.cos(self.theta) * self.a * math.sin(self.theta) * 2 + + +losange(3, 1).surface() + + +######################################## +# Le sens de l'héritage dépend de vos besoins. Si l'héritage porte principalement +# sur les méthodes, il est préférable de partir du plus général pour aller +# au plus spécifique. La première classe sert d'interface pour toutes ses filles. +# Si l'héritage porte principalement sur les attributs, il est préférable de +# partir du plus spécifique au plus général. Dans le cas général, il n'y a pas +# d'héritage plus sensé qu'un autre mais pour un problème donné, +# il y a souvent un héritage plus sensé qu'un autre. +# +# Précision des calculs +# ===================== +# +# Voici un aperçu de la précision des calculs pour le calcul :math:`1 - 10^{-n}`. +# L'exercice a pour but de montrer que l'ordinateur ne fait que des calculs approchés +# et que la précision du résultat dépend de la méthode numérique employée. + + +x = 1.0 +for i in range(0, 19): + x = x / 10 + print(i, "\t", 1.0 - x, "\t", x, "\t", x ** (0.5)) + + +######################################## +# Le programme montre que l'ordinateur affiche ``1`` +# lorsqu'il calcule :math:`1-10^{-17}`. +# Cela signifie que la précision des calculs en *python* +# est au mieux de :math:`10^{-16}`. +# C'est encore moins bon dans le cas de *float* ou +# réel simple précision codé sur +# 4 octets au lieu de 8 pour les *double*. + + +x = numpy.float32(1.0) +for i in range(0, 19): + x = x / numpy.float32(10) + print(i, "\t", 1.0 - x, "\t", x, "\t", x ** (0.5)) + + +######################################## +# On écrit une classe ``matrice_carree_2`` +# qui représente une matrice carrée de dimension 2. + + +class matrice_carree_2: + def __init__(self, a, b, c, d): + self.a, self.b, self.c, self.d = a, b, c, d + + def determinant(self): + return self.a * self.d - self.b * self.c + + +m1 = matrice_carree_2(1.0, 1e-6, 1e-6, 1.0) +m2 = matrice_carree_2(1.0, 1e-9, 1e-9, 1.0) +print(m1.determinant()) +print(m2.determinant()) + + +######################################## +# La seconde valeur est donc fausse. On considère maintenant la matrice +# :math:`M = \left(\begin{array}{cc} 1 & 10^{-9} \\ 10^{-9} & 1 \end{array} \right)`. +# +# On pose :math:`D = \det(M) = 1 - 10^{-18}` et :math:`T = tr(M) = 2`. :math:`\Delta` +# est le déterminant de *M* et *T* sa trace. On sait que les valeurs propres de +# *M* notées :math:`\lambda_1`, :math:`\lambda_2` vérifient : +# +# .. math:: +# +# \begin{array}{lll} +# D &=& \lambda_1 \lambda_2 \\ +# T &=& \lambda_1 + \lambda_2 +# \end{array} +# +# On vérifie que :math:`(x - \lambda_1)(x - \lambda_2) = x^2 - x +# (\lambda_1 + \lambda_2) + \lambda_1 \lambda_2`. +# Les valeurs propres de $M$ sont donc solutions de l'équation : +# :math:`x^2 - T x + D = 0`. +# +# Le discriminant de ce polynôme est :math:`\Delta = T^2 - 4 D`. +# On peut donc exprimer les valeurs propres de la matrice *M* par : +# +# .. math:: +# +# \begin{array}{lll} +# \lambda_1 &=& \frac{T - \sqrt{\Delta}}{2} \\ +# \lambda_2 &=& \frac{T + \sqrt{\Delta}}{2} +# \end{array} +# +# On ajoute donc la méthode suivante à la classe ``matrice_carree_2`` : + + +class matrice_carree_2: + def __init__(self, a, b, c, d): + self.a, self.b, self.c, self.d = a, b, c, d + + def determinant(self): + return self.a * self.d - self.b * self.c + + def valeurs_propres(self): + det = self.determinant() + trace = self.a + self.d + delta = trace**2 - 4 * det + l1 = 0.5 * (trace - (delta ** (0.5))) + l2 = 0.5 * (trace + (delta ** (0.5))) + return l1, l2 + + +m1 = matrice_carree_2(1.0, 1e-6, 1e-6, 1.0) +m2 = matrice_carree_2(1.0, 1e-9, 1e-9, 1.0) +print(m1.valeurs_propres()) +print(m2.valeurs_propres()) + + +######################################## +# D'après l'énoncé, les valeurs propres de la matrice :math:`M_2` sont les +# sommes de celles de la matrice *I* et de la matrice :math:`M'_2`. +# Par conséquent, ce second calcul mène au résultat suivant : +# +# :: +# +# l1 = 1-1e-9 = 0.99999999900000002828 +# l2 = 1+ 1e-9 = 1.000000001 +# +# La précision des calculs prend sont importance ici. On décompose la matrice +# :math:`M = \left(\begin{array}{cc} 1 & 0 \\ 0 & 1 \end{array}\right) + +# \left(\begin{array}{cc} 0 & 10^{-9} \\ 10^{-9} & 0 \end{array}\right) = I + M'`. +# +# On peut démontrer que si $\lambda$ est une valeur propre de :math:`M'`, +# alors :math:`1 + \lambda` est une valeur propre de *M*. +# Que donne le calcul des valeurs propres de $M'$ si on utilise la méthode +# ``valeurs_propres`` pour ces deux matrices ? +# +# On considère maintenant la matrice +# :math:`M'' = \left(\begin{array}{cc} 1 & 10^{-9} \\ -10^{-9} & 1 \end{array}\right)`. +# En décomposant la matrice :math:`M''` de la même manière qu'à la question 4, +# quelles sont les valeurs propres retournées par le programme pour la matrice +# :math:`M''` ? Quelles sont ses vraies valeurs propres ? +# +# La matrice :math:`M''` n'est en fait pas diagonalisable, c'est-à-dire que +# :math:`tr(M'')^2 - 4 \det{M''} = 4 - 4 (1 + 10^{-18}) < 0`. +# Or le calcul proposé par la question 3 aboutit au même résultat faux que pour +# la matrice :math:`M_2`, les deux valeurs propres trouvées seront égales à 1. +# Si on applique la décomposition proposée : +# :math:`M'' = I + \left(\begin{array}{cc}0&-10^{-9}\\ +# 10^{-9}&0\end{array}\right) = I + N''`. +# Le programme calcule sans erreur le discriminant négatif de la matrice :math:`N''` +# qui n'est pas diagonalisable. Il est donc impossible d'obtenir des valeurs +# propres réelles pour la matrice :math:`M''` avec cette seconde méthode. +# Cette question montre qu'une erreur d'approximation peut rendre une +# matrice diagonalisable alors qu'elle ne l'est pas. Il faut bien choisir +# cette précision en fonction de la destination des calculs. diff --git a/_doc/sphinxdoc/source/i_ex.rst b/_doc/i_ex.rst similarity index 100% rename from _doc/sphinxdoc/source/i_ex.rst rename to _doc/i_ex.rst diff --git a/_doc/i_faq.rst b/_doc/i_faq.rst new file mode 100644 index 00000000..0fc091f5 --- /dev/null +++ b/_doc/i_faq.rst @@ -0,0 +1,23 @@ + +.. _l-FAQ2: + +=== +FAQ +=== + +.. contents:: + :local: + +Langage Python +============== + +.. faqreflist:: + :contents: + :tag: python + +numpy +===== + +.. faqreflist:: + :contents: + :tag: numpy diff --git a/_doc/index.rst b/_doc/index.rst new file mode 100644 index 00000000..c095402c --- /dev/null +++ b/_doc/index.rst @@ -0,0 +1,73 @@ + +*en construction permanente* + +.. |gitlogo| image:: _static/git_logo.png + :height: 20 + +====================================== +Apprendre la programmation avec Python +====================================== + +Internet est une source quasi-infinie de documents, papiers, bouts de +code sur beaucoup de sujets mais il faut savoir picorer. +Ce site se veut plus facile à lire de façon traditionnelle, +un peu comme un livre. Il s'adresse surtout à ceux qui ne savent +pas ou eu programmer. +Il est aussi disponible en +`PDF `_ +(format brut de fonderie) et sur +`GitHub/teachpyx `_ |gitlogo|. + +.. toctree:: + :maxdepth: 1 + + introduction + c_lang/index + c_classes/index + c_exception/index + c_module/index + c_regex/index + c_parallelisation/index + c_gui/index + c_data/index + c_resume/index + api/index + i_ex + i_faq + auto_examples/index + defthe_index + license + CHANGELOGS + +L'intelligence artificielle est entrée dans le quotidien. +Machine learning, deep learning, la porte d'entrée se fait +par la programmation et principalement avec le langgage python. +Le site `Xavier Dupré `_ +contient beaucoup d'exemples sur beaucoup de sujets, +souvent reliés au machine learning. +Le contenu est sur `github `_. + +.. image:: https://ci.appveyor.com/api/projects/status/5jl303wl14dtesl0?svg=true + :target: https://ci.appveyor.com/project/sdpython/teachpyx + :alt: Build Status Windows + +.. image:: https://circleci.com/gh/sdpython/teachpyx/tree/master.svg?style=svg + :target: https://circleci.com/gh/sdpython/teachpyx/tree/master + +.. image:: https://badge.fury.io/py/teachpyx.svg + :target: https://pypi.org/project/teachpyx/ + +.. image:: https://img.shields.io/badge/license-MIT-blue.svg + :alt: MIT License + :target: http://opensource.org/licenses/MIT + +.. image:: https://codecov.io/github/sdpython/teachpyx/coverage.svg?branch=master + :target: https://codecov.io/github/sdpython/teachpyx?branch=master + +.. image:: http://img.shields.io/github/issues/sdpython/teachpyx.svg + :alt: GitHub Issues + :target: https://github.com/sdpython/teachpyx/issues + +.. image:: https://img.shields.io/github/repo-size/sdpython/teachpyx + :target: https://github.com/sdpython/teachpyx/ + :alt: size diff --git a/_doc/sphinxdoc/source/introduction.rst b/_doc/introduction.rst similarity index 85% rename from _doc/sphinxdoc/source/introduction.rst rename to _doc/introduction.rst index 4ba9ecca..ae57b8ce 100644 --- a/_doc/sphinxdoc/source/introduction.rst +++ b/_doc/introduction.rst @@ -4,8 +4,9 @@ Introduction ============ Ceci est une relecture du livre que j'ai écrit en 2009 -`Programmation avec le langage Python `_ -et disponible au format `PDF `_. +`Programmation avec le langage Python +`_ +écrit en 2011 avec une version de Python que plus personne n'utilise. La transcription du livre sous la forme d'un site web et d'un module python a permis d'automatiser la vérification des exemples pour assurer que ceux-ci fonctionnent encore avec les dernières @@ -16,7 +17,8 @@ Installation de Python Pour ceux qui débutent, je recommande l'utilisation de la distribution :epkg:`Anaconda`. Elle fonctionne sous Windows, -Linux et MacOS. Pour ceux qui souhaitent réduire la taille +Linux, MacOS. +Pour ceux qui souhaitent réduire la taille du premier téléchargement (> 500 Mo), elle existe en version allégée :epkg:`Miniconda`. Avec cette distribution, il est quasiment possible de tout faire grâce à une interface graphique. @@ -27,7 +29,7 @@ par rapport à cette dernière. C'est rarement un problème. En ce qui me concerne, je préfère la version officielle de :epkg:`Python`. Elle est moins gourmande sur le disque mais parfois plus difficile à maîtriser lors de l'installation de certaines -extensions. +extensions. Elle est installée par défault sur les distributions Linux. Installation d'extensions ou modules ou packages ================================================ @@ -53,8 +55,7 @@ il est préférable d'essayer d'abord : conda install -Les exemples de codes sont d'ailleurs disponibles sous la forme d'un module python -et des :ref:`notebooks ` accessibles sur le site. +Des exemples de codes sont d'ailleurs disponibles sous la forme d'un module python. :: @@ -68,7 +69,8 @@ Accents Le langage :epkg:`python` est conçu pour un monde anglophone et l'utilisation des accents ne va pas de soi. Le programme suivant qui demande d'afficher un message -contenant un accent provoque l'apparition d'une erreur : +contenant un accent peut provoquer l'apparition d'une erreur +selon les caractéristiques de votre machine. :: @@ -81,7 +83,7 @@ L'erreur est la suivante : File "essai.py", line 1 SyntaxError: Non-ASCII character '\xe9' in file i.py on line 1, but no encoding declared; - see http://www.python.org/peps/pep-0263.html for details + see https://peps.python.org/pep-0263/ for details Dans ce cas, il faut ajouter une ligne placée en première position qui précise que des accents pourront être utilisés. @@ -101,17 +103,28 @@ réservations d'hôtels, de trains ou d'avions même si aujourd'hui ce problème ne devrait plus en être un. Dans le cas contraire, cela donne une indication du côté vieillot voire obsolète d'une implémentation. -A cause des accents, la plupart des exemples cités dans ce -livre ne fonctionnent pas sans cette première ligne qui a +A cause des accents, les exemples cités dans ce +livre ne fonctionnent pas toujours sans cette première ligne qui a parfois été enlevée pour des questions de lisibilité. Il faut penser à l'ajouter pour reproduire les exemples. +Les dernières versions du langage Python autorisent maintenant la +présence de lettres accentuées dans les noms des variables, de fonctions +ou de classes. Néanmoins, c'est une mauvaise habitude à prendre +car beaucoup de langages ne le permettent pas. + L'instruction ``print(...)`` ordonne à l'ordinateur d'afficher un message à l'écran. Il n'a aucun impact sur son fonctionnement. Elle est beaucoup utilisée pour vérifier que le programme fait bien ce qu'il est supposé faire. +Une nouvelle version du langage Python est maintenant publiée chaque année. +L'ensemble des modifications est tenue à jour sur la page +`Python Enhancement Proposals (PEP) `_. +Chaque version est maintenue environ cinq ans selon un calendrier +précisé au moment de la sortie. + Trois concepts, séquence, test, boucle ====================================== diff --git a/_doc/license.rst b/_doc/license.rst new file mode 100644 index 00000000..f4b00c96 --- /dev/null +++ b/_doc/license.rst @@ -0,0 +1,7 @@ +.. _l-license: + +License +======= + +.. literalinclude:: LICENSE.txt + :language: none diff --git a/_doc/notebooks/README.txt b/_doc/notebooks/README.txt deleted file mode 100644 index 877bc788..00000000 --- a/_doc/notebooks/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Galleries -========= diff --git a/_doc/notebooks/numpy/README.txt b/_doc/notebooks/numpy/README.txt deleted file mode 100644 index 3e49bfc9..00000000 --- a/_doc/notebooks/numpy/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Ballades autour de numpy ------------------------- diff --git a/_doc/notebooks/numpy/numpy_tricks.ipynb b/_doc/notebooks/numpy/numpy_tricks.ipynb deleted file mode 100644 index 4897abdd..00000000 --- a/_doc/notebooks/numpy/numpy_tricks.ipynb +++ /dev/null @@ -1,303 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Points d'impl\u00e9mentation avec numpy\n", - "\n", - "Quelques \u00e9critures efficaces et non efficaces avec [numpy](http://www.numpy.org/)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "## acc\u00e9der \u00e0 un \u00e9l\u00e9ment en particulier" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 0., 1., 2., 3., 4.],\n", - " [10., 11., 12., 13., 14.],\n", - " [20., 21., 22., 23., 24.],\n", - " [30., 31., 32., 33., 34.],\n", - " [40., 41., 42., 43., 44.]])" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy\n", - "mat = numpy.zeros((5, 5))\n", - "for i in range(mat.shape[0]):\n", - " for j in range(mat.shape[1]):\n", - " mat[i, j] = i * 10 + j\n", - "mat" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(23.0, 23.0)" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mat[2, 3], mat[2][3]" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "116 ns \u00b1 4.49 ns per loop (mean \u00b1 std. dev. of 7 runs, 10000000 loops each)\n" - ] - } - ], - "source": [ - "%timeit mat[2, 3]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "319 ns \u00b1 57 ns per loop (mean \u00b1 std. dev. of 7 runs, 1000000 loops each)\n" - ] - } - ], - "source": [ - "%timeit mat[2][3]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Les deux \u00e9critures ont l'air identique puisqu'elle retourne le m\u00eame r\u00e9sultat. N\u00e9anmoins, ``mat[2][3]`` cr\u00e9e un tableau temporaire puis extrait un \u00e9l\u00e9ment. Les \u00e9l\u00e9ments ne sont pas recopi\u00e9s mais un objet interm\u00e9diaire est cr\u00e9\u00e9." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([20., 21., 22., 23., 24.])" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mat[2]" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.5" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} \ No newline at end of file diff --git a/_doc/notebooks/pandas/README.txt b/_doc/notebooks/pandas/README.txt deleted file mode 100644 index f3c8958a..00000000 --- a/_doc/notebooks/pandas/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Ballades autour de Pandas -------------------------- diff --git a/_doc/notebooks/pandas/pandas_groupby.ipynb b/_doc/notebooks/pandas/pandas_groupby.ipynb deleted file mode 100644 index 52817114..00000000 --- a/_doc/notebooks/pandas/pandas_groupby.ipynb +++ /dev/null @@ -1,413 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Pandas et groupby\n", - "\n", - "Petit tour de passe passe autour d'un [groupby](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html) et des valeurs manquantes qui ne sont plus prises en compte depuis les derni\u00e8res versions." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "## groupby et valeur manquantes" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
ab
01.02
110.020
2NaN3
3NaN4
\n", - "
" - ], - "text/plain": [ - " a b\n", - "0 1.0 2\n", - "1 10.0 20\n", - "2 NaN 3\n", - "3 NaN 4" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas\n", - "data = [{\"a\":1, \"b\":2}, {\"a\":10, \"b\":20}, {\"b\":3}, {\"b\":4}]\n", - "df = pandas.DataFrame(data)\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
b
a
1.02
10.020
\n", - "
" - ], - "text/plain": [ - " b\n", - "a \n", - "1.0 2\n", - "10.0 20" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.groupby(\"a\").sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Les valeurs manquantes ont disparu et c'est le comportement attendu d'apr\u00e8s [groupby and missing values](http://pandas-docs.github.io/pandas-docs-travis/groupby.html#na-and-nat-group-handling). Il est possible de ocrriger le tir avec la fonction impl\u00e9ment\u00e9 dans ce module." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
ab
01.02
110.020
2NaN7
\n", - "
" - ], - "text/plain": [ - " a b\n", - "0 1.0 2\n", - "1 10.0 20\n", - "2 NaN 7" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from pandas_streaming.df import pandas_groupby_nan\n", - "pandas_groupby_nan(df, \"a\").sum()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "L'astuce consiste \u00e0 remplacer les valeurs manquantes par d'autres non utilis\u00e9es dans le dataframe, \u00e0 grouper, puis \u00e0 leur redonner leur valeurs initiales. Le code de la fonction n'est pas tr\u00e8s propre car il modifie des variables que l'utilisateur n'est pas cens\u00e9 modifier. Il est possible que la fonction \"casse\" pour des versions ult\u00e9rieures. Le [code](https://github.com/sdpython/pandas_streaming/blob/master/src/pandas_streaming/df/dataframe_helpers.py#L301) utilise quelques variables non documentation du module [pandas](https://pandas.pydata.org/)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.5" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} \ No newline at end of file diff --git a/_doc/notebooks/python/README.txt b/_doc/notebooks/python/README.txt deleted file mode 100644 index 1170c633..00000000 --- a/_doc/notebooks/python/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -Ballades autour de Python -------------------------- - diff --git a/_doc/notebooks/python/float_and_double_rouding.ipynb b/_doc/notebooks/python/float_and_double_rouding.ipynb deleted file mode 100644 index 38a6c808..00000000 --- a/_doc/notebooks/python/float_and_double_rouding.ipynb +++ /dev/null @@ -1,1230 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Float conversion\n", - "\n", - "I came up with the following question $(float64)x < (float64)y \\Longrightarrow (float32) x < (float32)y$? What is the probability this holds?" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Probability (float64)x == (float32)x\n", - "\n", - "Let's evaluate how many time we draw a random double number equal to its float conversion." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((100000000,), dtype('float64'))" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import numpy\n", - "rnd = numpy.random.random(100000000)\n", - "rnd.shape, rnd.dtype" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rnd32 = rnd.astype(numpy.float32).astype(numpy.float64)\n", - "equal = (rnd == rnd32).sum()\n", - "equal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It is very low. Let's check the reverse is true." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "100000000" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rnd32b = rnd32.astype(numpy.float64).astype(numpy.float32)\n", - "equal = (rnd32b == rnd32).sum()\n", - "equal" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's study the distribution of the difference." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-2.9802321610539195e-08, 2.9802320611338473e-08)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "delta = rnd - rnd32\n", - "numpy.min(delta), numpy.max(delta)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(5.400330183036317e-10, 0.9999999976946683)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "numpy.min(rnd), numpy.max(rnd)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY0AAAEJCAYAAABohnsfAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAEvtJREFUeJzt3X+sZ3V95/HnSwaU2FpQroadHztknbRSUn/N4qRualdcGLRx6KYkkGaZuJNMarC1aZt1bJMl1SXB3aQ2bJQsWSYOjS1ltYbZOjhOEdM2AWWw/BBHyy1auYU46ACFmGrQ9/7x/cz69fq9937unTuc72Wej+Sb7znv8znn8zmZH6+cH99zUlVIktTjRUMPQJK0dhgakqRuhoYkqZuhIUnqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6rRt6AKvtnHPOqc2bNw89DElaU+69995vV9XMUu1ecKGxefNmDh8+PPQwJGlNSfKPPe08PSVJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnqZmhIz5PNez499BCkE2ZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6dYVGkm8keTDJfUkOt9rLkxxK8nD7PrvVk+T6JLNJHkjyhrHt7GztH06yc6z+xrb92bZuFutDkjSM5Rxp/Puqel1VbW3ze4A7qmoLcEebB7gU2NI+u4EbYBQAwDXAm4ALgWvGQuCG1vb4etuX6EOSNIATOT21A9jXpvcBl43Vb66Ru4GzkpwLXAIcqqpjVfUkcAjY3pa9rKruqqoCbp63rUl9SJIG0BsaBXw2yb1Jdrfaq6rqcYD2/cpWXw88OrbuXKstVp+bUF+sD0nSANZ1tntzVT2W5JXAoSRfXaRtJtRqBfVuLch2A2zatGk5q0qSlqHrSKOqHmvfR4FPMbom8a12aon2fbQ1nwM2jq2+AXhsifqGCXUW6WP++G6sqq1VtXVmZqZnlyRJK7BkaCR5aZKfPj4NXAx8GdgPHL8DaidwW5veD1zV7qLaBjzdTi0dBC5Ocna7AH4xcLAteybJtnbX1FXztjWpD0nSAHpOT70K+FS7C3Yd8KdV9Zkk9wC3JtkFfBO4vLU/ALwdmAW+C7wLoKqOJfkgcE9r94GqOtam3w18DDgTuL19AK5boA9J0gCWDI2qegR47YT6d4CLJtQLuHqBbe0F9k6oHwYu6O1DkjQMfxEuSepmaEiSuhkakqRuhoYkqZuhIUnqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnq1h0aSU5L8ndJ/rLNn5fkC0keTvLnSc5o9Re3+dm2fPPYNt7f6l9LcslYfXurzSbZM1af2IckaRjLOdJ4L3BkbP5DwIeragvwJLCr1XcBT1bVq4EPt3YkOR+4Avh5YDvw0RZEpwEfAS4FzgeubG0X60OSNICu0EiyAXgH8L/bfIC3Ap9oTfYBl7XpHW2etvyi1n4HcEtVfa+qvg7MAhe2z2xVPVJV3wduAXYs0YckaQC9Rxp/DPwX4Idt/hXAU1X1XJufA9a36fXAowBt+dOt/f+vz1tnofpifUiSBrBkaCT5FeBoVd07Xp7QtJZYtlr1SWPcneRwksNPPPHEpCbSoDbv+fTQQ5BWRc+RxpuBdyb5BqNTR29ldORxVpJ1rc0G4LE2PQdsBGjLfwY4Nl6ft85C9W8v0sePqaobq2prVW2dmZnp2CVJ0kosGRpV9f6q2lBVmxldyP5cVf06cCfwa63ZTuC2Nr2/zdOWf66qqtWvaHdXnQdsAb4I3ANsaXdKndH62N/WWagPSdIATuR3Gu8DfifJLKPrDze1+k3AK1r9d4A9AFX1EHAr8BXgM8DVVfWDds3iPcBBRndn3draLtaHJGkA65Zu8iNV9Xng8236EUZ3Ps1v8y/A5Qusfy1w7YT6AeDAhPrEPiRJw/AX4ZKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnqZmhIkroZGpKkboaGJKmboSGdZOOvevW1r1rrDA1JUjdDQ5LUzdCQnmeeotJaZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqduSoZHkJUm+mOT+JA8l+cNWPy/JF5I8nOTPk5zR6i9u87Nt+eaxbb2/1b+W5JKx+vZWm02yZ6w+sQ9J0jB6jjS+B7y1ql4LvA7YnmQb8CHgw1W1BXgS2NXa7wKerKpXAx9u7UhyPnAF8PPAduCjSU5LchrwEeBS4HzgytaWRfqQJA1gydCokWfb7OntU8BbgU+0+j7gsja9o83Tll+UJK1+S1V9r6q+DswCF7bPbFU9UlXfB24BdrR1FupDkjSArmsa7YjgPuAocAj4B+CpqnquNZkD1rfp9cCjAG3508Arxuvz1lmo/opF+pCmno9A1wtRV2hU1Q+q6nXABkZHBq+Z1Kx9Z4Flq1X/CUl2Jzmc5PATTzwxqYk0iIWCY/OeTxsqWpOWdfdUVT0FfB7YBpyVZF1btAF4rE3PARsB2vKfAY6N1+ets1D924v0MX9cN1bV1qraOjMzs5xdkiQtQ8/dUzNJzmrTZwJvA44AdwK/1prtBG5r0/vbPG3556qqWv2KdnfVecAW4IvAPcCWdqfUGYwulu9v6yzUhyRpAOuWbsK5wL52l9OLgFur6i+TfAW4Jcl/A/4OuKm1vwn4kySzjI4wrgCoqoeS3Ap8BXgOuLqqfgCQ5D3AQeA0YG9VPdS29b4F+pAkDWDJ0KiqB4DXT6g/wuj6xvz6vwCXL7Cta4FrJ9QPAAd6+5AkDcNfhEuSuhkakqRuhoZ0Eng7rV6oDA1JUjdDQ5LUzdCQJHUzNCRJ3QwNSVI3Q0OS1M3QkCR1MzQkSd0MDUlSN0NDktTN0JBWwfE38Z3I40N89IjWgozedfTCsXXr1jp8+PDQw9ApZjX/w//Gde9YtW1JvZLcW1Vbl2rnkYYkqZuhIUnqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIZ0gH2muU8mSoZFkY5I7kxxJ8lCS97b6y5McSvJw+z671ZPk+iSzSR5I8oaxbe1s7R9OsnOs/sYkD7Z1rk+SxfqQJA2j50jjOeB3q+o1wDbg6iTnA3uAO6pqC3BHmwe4FNjSPruBG2AUAMA1wJuAC4FrxkLghtb2+HrbW32hPiRJA1gyNKrq8ar6Upt+BjgCrAd2APtas33AZW16B3BzjdwNnJXkXOAS4FBVHauqJ4FDwPa27GVVdVeN3gh187xtTepDkjSAdctpnGQz8HrgC8CrqupxGAVLkle2ZuuBR8dWm2u1xepzE+os0sf8ce1mdKTCpk2blrNL0qLmX6/4xnXv+LHayXjL3vHtj/f1fPQr9ei+EJ7kp4BPAr9dVf+8WNMJtVpBvVtV3VhVW6tq68zMzHJWlZZlfoiczIvg49v2YrumRVdoJDmdUWB8vKr+opW/1U4t0b6PtvocsHFs9Q3AY0vUN0yoL9aHJGkAPXdPBbgJOFJVfzS2aD9w/A6oncBtY/Wr2l1U24Cn2ymmg8DFSc5uF8AvBg62Zc8k2db6umretib1IUkaQM81jTcD/wl4MMl9rfb7wHXArUl2Ad8ELm/LDgBvB2aB7wLvAqiqY0k+CNzT2n2gqo616XcDHwPOBG5vHxbpQ5I0gCVDo6r+lsnXHQAumtC+gKsX2NZeYO+E+mHgggn170zqQ5I0DH8RLknqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnqtqzXvUprwanwlrvV3EdfHavl8EhDktTN0JAkdTM0JEndDA1JUjdDQ5LUzdCQJHUzNCRJ3QwNSVI3Q0OS1M3QkCR1MzQkSd0MDUlSN0NDktTN0JAkdVsyNJLsTXI0yZfHai9PcijJw+377FZPkuuTzCZ5IMkbxtbZ2do/nGTnWP2NSR5s61yfJIv1IUkaTs+RxseA7fNqe4A7qmoLcEebB7gU2NI+u4EbYBQAwDXAm4ALgWvGQuCG1vb4etuX6EOSNJAlQ6Oq/ho4Nq+8A9jXpvcBl43Vb66Ru4GzkpwLXAIcqqpjVfUkcAjY3pa9rKruqqoCbp63rUl9SJIGstJrGq+qqscB2vcrW3098OhYu7lWW6w+N6G+WB+SpIGs9uteM6FWK6gvr9NkN6NTXGzatGm5q2uFToXXqp4KpvXP0dfQTqeVHml8q51aon0fbfU5YONYuw3AY0vUN0yoL9bHT6iqG6tqa1VtnZmZWeEuSZKWstLQ2A8cvwNqJ3DbWP2qdhfVNuDpdmrpIHBxkrPbBfCLgYNt2TNJtrW7pq6at61JfUiSBrLk6akkfwb8MnBOkjlGd0FdB9yaZBfwTeDy1vwA8HZgFvgu8C6AqjqW5IPAPa3dB6rq+MX1dzO6Q+tM4Pb2YZE+JEkDWTI0qurKBRZdNKFtAVcvsJ29wN4J9cPABRPq35nUhyRpOP4iXJLUzdCQJHUzNCRJ3QwNSVI3Q0OS1M3QkCR1MzQkSd0MDUlSN0NDktTN0JAkdTM0JEndDA1JUjdDQ5LUzdCQJHVb7de9rmnT+tpL6VTkv8fleb5ej+uRhiSpm6EhSepmaEiSuhkakqRuhoYkqZuhIUnqZmhIkroZGpKkboaGJKmboSFJ6mZoSJK6GRqSpG6GhiSpm6EhSeo29aGRZHuSryWZTbJn6PFI0qlsqkMjyWnAR4BLgfOBK5OcP+yoJOnUNdWhAVwIzFbVI1X1feAWYMfAY5KkU9a0h8Z64NGx+blWkyQNYNpf95oJtfqJRsluYHebfTbJ11bQ1znAt1ew3jRyX6aT+zKdXhD7kg8BJ7Yv/7qn0bSHxhywcWx+A/DY/EZVdSNw44l0lORwVW09kW1MC/dlOrkv08l9WZ5pPz11D7AlyXlJzgCuAPYPPCZJOmVN9ZFGVT2X5D3AQeA0YG9VPTTwsCTplDXVoQFQVQeAA89DVyd0emvKuC/TyX2ZTu7LMqTqJ64rS5I00bRf05AkTRFDY0ySDyZ5IMl9ST6b5F8NPaaVSvI/kny17c+nkpw19JhWKsnlSR5K8sMka/IulxfK43CS7E1yNMmXhx7LiUqyMcmdSY60v1/vHXpMK5XkJUm+mOT+ti9/eNL68vTUjyR5WVX9c5v+LeD8qvqNgYe1IkkuBj7Xbib4EEBVvW/gYa1IktcAPwT+F/B7VXV44CEtS3sczt8D/4HRbeT3AFdW1VcGHdgKJPkl4Fng5qq6YOjxnIgk5wLnVtWXkvw0cC9w2Rr9cwnw0qp6NsnpwN8C762qu1e7L480xhwPjOalTPgh4VpRVZ+tqufa7N2MfuOyJlXVkapayQ82p8UL5nE4VfXXwLGhx7EaqurxqvpSm34GOMIafeJEjTzbZk9vn5Py/5ehMU+Sa5M8Cvw68F+HHs8q+c/A7UMP4hTm43CmXJLNwOuBLww7kpVLclqS+4CjwKGqOin7csqFRpK/SvLlCZ8dAFX1B1W1Efg48J5hR7u4pfaltfkD4DlG+zO1evZlDet6HI6GkeSngE8Cvz3vbMOaUlU/qKrXMTqrcGGSk3L6cOp/p7HaquptnU3/FPg0cM1JHM4JWWpfkuwEfgW4qKb84tUy/lzWoq7H4ej5187/fxL4eFX9xdDjWQ1V9VSSzwPbgVW/YeGUO9JYTJItY7PvBL461FhOVJLtwPuAd1bVd4cezynOx+FMoXbx+CbgSFX90dDjORFJZo7fIZnkTOBtnKT/v7x7akySTwI/y+hOnX8EfqOq/mnYUa1MklngxcB3WunuNXwn2K8C/xOYAZ4C7quqS4Yd1fIkeTvwx/zocTjXDjykFUnyZ8AvM3qa6reAa6rqpkEHtUJJ/h3wN8CDjP7NA/x+ewrFmpLkF4B9jP5+vQi4tao+cFL6MjQkSb08PSVJ6mZoSJK6GRqSpG6GhiSpm6EhSVNstR8SmeS/t4caHklyfbv1uJuhIUnT7WOMfqh3wpL8IvBm4BeAC4B/C7xlOdswNCRpik16SGSSf5PkM0nuTfI3SX6ud3PAS4AzGP2O63RGv7fpZmhI0tpzI/CbVfVG4PeAj/asVFV3AXcCj7fPwao6spyOT7lnT0nSWtYesPiLwP8Zuxzx4rbsPwKTfgn+T1V1SZJXA6/hR69KOJTkl9rRTBdDQ5LWlhcBT7Un2v6Y9tDFxR68+KuMHin0LECS24FtQHdoeHpKktaQ9vj2rye5HEYPXkzy2s7Vvwm8Jcm69oTftzB6+VQ3Q0OSplh7SORdwM8mmUuyi9FL4nYluR94iP43QX4C+AdGD2m8H7i/qv7vssbjAwslSb080pAkdTM0JEndDA1JUjdDQ5LUzdCQJHUzNCRJ3QwNSVI3Q0OS1O3/AS6NBzBLlAvJAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "plt.hist(delta, bins=1000);" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We finally check that double operations between float numpers remain floats." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "for i in range(0,100000):\n", - " i,j = random.randint(0, len(rnd32)-1), random.randint(0, len(rnd32)-1)\n", - " d32 = numpy.float64(rnd32[i] * rnd32[j])\n", - " d64 = numpy.float64(rnd32[i]) * numpy.float64(rnd32[j])\n", - " if d32 != d64:\n", - " raise Exception(\"Issue with somme={0} = {1} + {2}\".format(rnd32[i] + rnd32[j], rnd32[i], rnd32[j]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Interval length distribution\n", - "\n", - "Let's imagine now we want to define an intervalle in which a double is converted to the same float. Let's find out about it length." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(7.245554200022153e-12, 5.9604641222676946e-08)" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def find_interval(x):\n", - " dx = numpy.abs(x - numpy.float32(x)) # usually not zero\n", - " dx /= 100\n", - " f = numpy.float32(x)\n", - " x1 = x\n", - " while numpy.float32(x1) == f:\n", - " x1 -= dx\n", - " x2 = x\n", - " while numpy.float32(x2) == f:\n", - " x2 += dx\n", - " return x1 + dx, x2 - dx\n", - "\n", - "length = numpy.zeros((2000,))\n", - "for i in range(length.shape[0]):\n", - " x = rnd[i]\n", - " x1, x2 = find_interval(x)\n", - " length[i] = x2-x1 \n", - "\n", - "min(length), max(length)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.hist(length, bins=50);" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So we can approximate this interval by something like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5.953141313241872e-08" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ql = numpy.sort(length)[int(length.shape[0] * 0.8)]\n", - "ql" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## An answer to the initial question\n", - "\n", - "Let's estimate $\\mathbb{P}\\left(x_{64} < y_{64} \\Longrightarrow x_{32} < y_{32} \\; | \\; |x-y| \\leqslant d\\right)$ ?" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "90 5.357827181917685e-08 : 638 991\n", - "190 1.1310968495159557e-07 : 812 1018\n", - "290 1.726410980840143e-07 : 889 1011\n", - "390 2.32172511216433e-07 : 918 986\n", - "490 2.9170392434885173e-07 : 901 981\n", - "590 3.5123533748127045e-07 : 936 986\n", - "690 4.1076675061368917e-07 : 964 1004\n", - "790 4.702981637461079e-07 : 982 1021\n", - "890 5.298295768785266e-07 : 964 998\n", - "990 5.893609900109453e-07 : 946 975\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dratiototal
05.953141e-100.019447977
11.190628e-090.041879979
21.785942e-090.065590991
32.381257e-090.0630001000
42.976571e-090.072217997
\n", - "
" - ], - "text/plain": [ - " d ratio total\n", - "0 5.953141e-10 0.019447 977\n", - "1 1.190628e-09 0.041879 979\n", - "2 1.785942e-09 0.065590 991\n", - "3 2.381257e-09 0.063000 1000\n", - "4 2.976571e-09 0.072217 997" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas\n", - "\n", - "def inf_strict(x, y):\n", - " f1 = x < y\n", - " f2 = numpy.float32(x) < numpy.float32(y)\n", - " return f1, f2\n", - "\n", - "def count_events(fct):\n", - " rows = []\n", - " for di in range(1, 1001):\n", - " d = di * ql / 100\n", - " total = 0\n", - " ok = 0\n", - " rnd = numpy.random.random((2000*3,))\n", - " for i in range(0, rnd.shape[0], 3):\n", - " s = -1 if rnd[i+2] < 0.5 else 1\n", - " x, y = rnd[i], rnd[i] + rnd[i+1]*d*s\n", - " f1, f2 = fct(x, y)\n", - " if f1: \n", - " total += 1\n", - " if f2:\n", - " ok += 1\n", - " if (di+10) % 100 == 0:\n", - " print(di, d, \":\", ok, total)\n", - " rows.append(dict(d=d, ratio=ok*1./total, total=total))\n", - "\n", - " return pandas.DataFrame(rows)\n", - "\n", - "df = count_events(inf_strict)\n", - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "df.plot(x=\"d\", y=\"ratio\")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "df.plot(x=\"d\", y=\"ratio\", logx=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## An answer to a similar question: what about not strict comparison?\n", - "\n", - "Let's estimate $\\mathbb{P}\\left(x_{64} \\leqslant y_{64} \\Longrightarrow x_{32} \\leqslant y_{32} \\; | \\; |x-y| \\leqslant d\\right)$ ?" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "90 5.357827181917685e-08 : 966 966\n", - "190 1.1310968495159557e-07 : 1015 1015\n", - "290 1.726410980840143e-07 : 1004 1004\n", - "390 2.32172511216433e-07 : 991 991\n", - "490 2.9170392434885173e-07 : 1015 1015\n", - "590 3.5123533748127045e-07 : 975 975\n", - "690 4.1076675061368917e-07 : 969 969\n", - "790 4.702981637461079e-07 : 962 962\n", - "890 5.298295768785266e-07 : 1032 1032\n", - "990 5.893609900109453e-07 : 1000 1000\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dratiototal
05.953141e-101.0996
11.190628e-091.0969
21.785942e-091.01004
32.381257e-091.0979
42.976571e-091.01041
\n", - "
" - ], - "text/plain": [ - " d ratio total\n", - "0 5.953141e-10 1.0 996\n", - "1 1.190628e-09 1.0 969\n", - "2 1.785942e-09 1.0 1004\n", - "3 2.381257e-09 1.0 979\n", - "4 2.976571e-09 1.0 1041" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def inf_equal(x, y):\n", - " f1 = x <= y\n", - " f2 = numpy.float32(x) <= numpy.float32(y)\n", - " return f1, f2\n", - "\n", - "df2 = count_events(inf_equal)\n", - "df2.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "ax = df.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<\")\n", - "df2.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<=\", ax=ax)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "90 5.357827181917685e-08 : 652 1008\n", - "190 1.1310968495159557e-07 : 799 964\n", - "290 1.726410980840143e-07 : 871 994\n", - "390 2.32172511216433e-07 : 881 969\n", - "490 2.9170392434885173e-07 : 961 1014\n", - "590 3.5123533748127045e-07 : 906 958\n", - "690 4.1076675061368917e-07 : 930 973\n", - "790 4.702981637461079e-07 : 1004 1036\n", - "890 5.298295768785266e-07 : 962 1012\n", - "990 5.893609900109453e-07 : 972 1016\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dratiototal
05.953141e-100.024291988
11.190628e-090.044838959
21.785942e-090.0577691004
32.381257e-090.0870001000
42.976571e-090.0917691057
\n", - "
" - ], - "text/plain": [ - " d ratio total\n", - "0 5.953141e-10 0.024291 988\n", - "1 1.190628e-09 0.044838 959\n", - "2 1.785942e-09 0.057769 1004\n", - "3 2.381257e-09 0.087000 1000\n", - "4 2.976571e-09 0.091769 1057" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def sup_strict(x, y):\n", - " f1 = x > y\n", - " f2 = numpy.float32(x) > numpy.float32(y)\n", - " return f1, f2\n", - "\n", - "df3 = count_events(sup_strict)\n", - "df3.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "ax = df.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<\")\n", - "df2.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<=\", ax=ax)\n", - "df3.plot(x=\"d\", y=\"ratio\", logx=True, label=\">\", ax=ax)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "90 5.357827181917685e-08 : 964 964\n", - "190 1.1310968495159557e-07 : 1010 1010\n", - "290 1.726410980840143e-07 : 1009 1009\n", - "390 2.32172511216433e-07 : 990 990\n", - "490 2.9170392434885173e-07 : 967 967\n", - "590 3.5123533748127045e-07 : 1019 1019\n", - "690 4.1076675061368917e-07 : 1013 1013\n", - "790 4.702981637461079e-07 : 1020 1020\n", - "890 5.298295768785266e-07 : 996 996\n", - "990 5.893609900109453e-07 : 964 964\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dratiototal
05.953141e-101.01031
11.190628e-091.01013
21.785942e-091.0975
32.381257e-091.0998
42.976571e-091.01022
\n", - "
" - ], - "text/plain": [ - " d ratio total\n", - "0 5.953141e-10 1.0 1031\n", - "1 1.190628e-09 1.0 1013\n", - "2 1.785942e-09 1.0 975\n", - "3 2.381257e-09 1.0 998\n", - "4 2.976571e-09 1.0 1022" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def sup_equal(x, y):\n", - " f1 = x >= y\n", - " f2 = numpy.float32(x) >= numpy.float32(y)\n", - " return f1, f2\n", - "\n", - "df4 = count_events(sup_equal)\n", - "df4.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEOCAYAAABy7Vf3AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvAOZPmwAAIABJREFUeJzt3Xl8lNW9x/HPmclkX8gGJISQhH2HGhE3RAUXiqDWBZeKorW2emtt7RW9XrG2t7X2Xq22Xi0CIloXtFRxofaquKAiBEE22bcECCQBsi+TmXP/SAxbIAtJZjLzfb9evJznec488xsf8s3hzDPnGGstIiISWBy+LkBERNqewl1EJAAp3EVEApDCXUQkACncRUQCkMJdRCQAKdxFRAKQwl1EJAAp3EVEApDCXUQkAIX46oWTkpJsRkaGr15eRKRTWrFiRaG1Nrmpdj4L94yMDHJycnz18iIinZIxZmdz2mlYRkQkACncRUQCkMJdRCQAKdxFRAJQk+FujJljjNlvjFl7guPGGPOUMWaLMWa1MeZ7bV+miIi0RHN67nOBS05y/FKgb/2f24FnTr0sERE5FU3eCmmt/dQYk3GSJpOBebZuvb6lxpguxpgUa+3eNqrxKPm3f5/q7Xva49QiIh0iLDOV7jPfbdfXaIsx9x5A7hHbefX7jmOMud0Yk2OMySkoKGiDlxYRkca0xZeYTCP7Gl1121o7E5gJkJ2d3aqVudv7t52ISCBoi557HtDziO00QOMmIiI+1BbhvhC4qf6umdFAcXuNt4uIdGab9pXy8le7OuS1mhyWMca8AowFkowxecAMwAVgrX0WeA+YAGwBKoBb2qtYEZHOoLjSTZXbw/6KfbhC3Fz97hUAVOTehKdsED84rQdhIc52raE5d8tc18RxC9zZZhWJiPi50io3i7b/k+25KUwa2o9KxxaGJg3lzgWvs3tvT9btKcEZtYnI9DlHPS+y5zxqDpzFkx/05t8vGdCuNfpsVkgREV8qri4mLiyuyXZ7DlUS7nJyoGYXYSFhuKujuXj2fxPefSEALx0zCF3jOZOYgV+e8HyhCV/w4poM/v2S+0+p/qYo3EUk6Hy06yPuXnw38y6dx8iuI487nluSy9/Wv07PuG785/xiQiK3Etb1Xw3Hw7uf+NyhCScO9u+4kv4FKNxFRNrUin0rAFhdsLoh3L1ey/Nf7OCCwWFMWjihoW1URtu/fnbiyb703zY0cZiIBB2nqfsw88NdHzbsu+uVFTy2/FEmLby43V9/bJ/0dn8N9dxFJChsPriZCc/+jQv79+Lz0ucBWLl/JZkPvkx0398DEJrQPq+dGjacod3T+HRFb3459jx+MCCrfV7oCAp3EQlIr296nb5d+nLD07n8dGx/nt31A8JT4fPSo9t9F+xtrWzLvbx8yzhGZ6ZiTP0X+ce2y0s1SuEuIp3a7rLdbD64mbE9xzbse3XZLv7r20cAcGTBs234vaGaA6MJTVgKQNmmB8FZSVTGXzDO6qPaPXPtxZyZdZJPXtuZwl1EOrWpi6ayr2IfUwfeTp/obP5n9b9TsD8DV9N3ObbKxnue4/I3L2d06mimT70WgDlLzmNoWgzfS49nxIsjALhkiO+CHcDUfQep42VnZ9ucnByfvLaIBIYDVQc477XzGrZrKzIIidxxSucs3/5TbG0cxlGF9UaQ0XM7heGv0C2sL0+N/y2DEged9Plz185lRNcRjOg64pTqOBFjzAprbXZT7dRzF5FO6+cf/fyo7VMJdqeN4dyep7FqX39yD1Ty959eypSZS/njxT+md/efEB8e36zz3Dzk5lbX0JYU7iLSKRRUFLA8fzll7jIm9Z5EVW0VKwtWttn5fzxiGj8ZcRu1Y70AhDgdbPrtpW12/o6mcBcRv7fz0D4mvjWuYfs3S3/Toud7qlJwhtfNExBVOY5bhkzl1rOG8MXWIn617Eoqaku4dehNQF2oBwKFu4j4jY827CMuwsVpvY6+4fzSV6bhjGz9eSt2/JSoPo9hTC3ZsT/kx+fUjYeP6duNJb0/Bgsup+sUKvc/gfErSkQCwrS5OfzgmS8pqChg4hvXsrVoH9ZaHOEtX/+ne9gAlkxZwuOjFoF10bvqUco2PUhoyNGx53K4Ai7YQT13Eelgbo8bh3HgdNRNAbCnbA9dwrrwh+V/IKzbPqr3X8JV/7iNA7XbuPHvv2XCwEEYR23TJ66Ng5BiLs28lMfGPNawe/zAON6+K4b+3WP44/sb+OnYPu311vyKboUUkQ419IWhnJ16Ns+Of7Zhuy1EmRQWXDmXpIgkQp2hbXJOf9TcWyE1LCMiHe7zPZ8D8MHOD1r1/Jqis/HWJDZsh5hw5kx4itTo1IAO9pZQuIuIT1hruefje1r13Or9l1G+7WcN2ytvWs6gpPZd2aizUbiLiE+8tHxNi59TtulBXrj45boNqx76yegDVRHpMF9tK2p4/Ie10zDNWCPa647B4SolIzaT1x++inCXE9gFGM7ucTZX97263ertzBTuItIhnvxgM3M+3w4ZddvHzqJ4Im9c/hLXvDuZO4b/uD7YYUy/ZIakxvLv455tp2o7P4W7iLQ7j9fyp4+XExK7mvAWPG/VD1fhdDhZM/XoIZx500a1bYEBSOEuIu1q88HNfLHBNmtRjHhXKiWlsXjCNwA03AsvLadwF5F2cf9n9/NJ7ieUukvx1iTgaMbnn1OHXsPUQbcw8qXh7V9ggNPdMiLSJrxey89eWUnOjgMAvLPtHUrddWvaOUIPNOscDuMImIm7fE3/F0XklJXVlLGreD8Lv9nDlFf+wgtfbmjR86/MqpuRMcwZ1h7lBSUNy4hIi3mtlwp3BTM/3s3QtC48tOpyytxlOMLvIiL1dX6/fGOLlrm7b/SdJESFclW/qwB478r3cDkCbzKvjqRwF5EWe+abZ3j2m2cp3TgD46wguk8ZAMZRA4ArbnWjz7sgdTIf7XkLgOmjpmMwXJB+AZGuSO7+3t0N7XrG9GzndxD4FO4i0mJvb30bAOOsIDzlHw37I3vNbLR9fFg8B6sPkhwTzmVZl3Gw+iA3DLyhQ2oNVgp3EWkxj/UAYEwtjrC9TbYfkzaGt7bW9dh/d+7v2rU2qaMPVEWkRT7etob88nwAono/gSOkvMnn/HDQDwG4MP3Cdq1NDmtWz90YcwnwJOAEZllrHz3meDrwAtClvs10a+17bVyriPjQqv2rOFR9iDs/eoCWfNY5Mvl0+if0P+5bptK+mgx3Y4wTeBoYD+QBy40xC621649o9iAw31r7jDFmEPAeDTNIiEhnZ63lh4vqet+mGUvS9Q29kq/XDGXH765q79LkBJrTcx8FbLHWbgMwxrwKTAaODHcLxNY/jgNavuChiPit3311eJzcONwnbGdrI0mKSObvUx7GXGc6ojQ5geaMufcAco/Yzqvfd6SHgRuNMXnU9dr/rU2qE5EOV13rIWP6uzz/+faGfa9ufPWkz6kpOpsB7t9TtvkhpvR4EmMU7L7WnHBv7Codu/DqdcBca20aMAF40Rhz3LmNMbcbY3KMMTkFBQUtr1ZE2l1pVd1i1E99soz9FXXfOm1M1b4JALhLhlC9/zIennAuAOMGduuYQuWkmhPuecCR3yhI4/hhl1uB+QDW2i+BcCDp2BNZa2daa7OttdnJycmtq1hE2lWtp67vVtvjt1z4+oW88tWuRtt5a7rWP6rr/w1OjWPHo9+nT9fojihTmtCcMfflQF9jTCawG5gCXH9Mm13AhcBcY8xA6sJdXXORTqjS7Tlqu8Yef6vj0xc+zZmpZ/J4Ti3F+ecw5vzeHVWeNFOT4W6trTXG3AW8T91tjnOsteuMMY8AOdbahcAvgeeMMfdQN2Rzs7X22KEbEekE1hetA0dVw/a6mtm4jllhY1jSMFwOF/eNuq+Dq5PmatZ97vX3rL93zL6Hjni8Hji7bUsTkY5kraXCXcX0pbcS0aNvw35X7PH3p0e5ojqyNGkFfUNVRAC4+fnlDP3tKwCERG8+7njFztsbHruaca+7+JbmlhERAD7ZVIAzuuiEx0M9PUh338V5w4s7sCppLYW7iPBJ7ie4uiwFU3vCNusevhzH8Xc4i5/SlRIR7vroLsJT3sQRtr9hn6c6mZoDZzVsK9g7F10tEWkQGr+s4bGtjaF630SchDIieYQPq5LW0LCMSBDbXrydl9e/cdQ+6wnFOGtIi49gUv8BXDd6MTHhWtu0s1G4iwShwrJqbpk/ix3OZ4875i4+jdCEL4mKqOLfLuzbyLOlM9CwjEgQem35rkaDHaC2ZCgAZe6yjixJ2pjCXSTIeLwe/rrrxPOs/9eEugnBvls9STonDcuIBIHCykL2lu1laPJQDlUfwuI9Ydspp/dmyulaNamzU7iLBIGrFl5FUVURS6espLCy0NflSAfQsIxIgFv4zR6Kquq+eTrk4X+yOHfxcW287piOLkvamcJdJMD97+ItDY9Du73J06uePq5Nxa66eWMmZk3ssLqkfSncRQJcrffw7Nuh8V8dd/ze7HtJjUyndOMMfnP2bzqyNGlHGnMXCXC1nuM/PE0gm9tPv4SzeoyiV2wvrulrcXu9hDgUCYFCV1IkwLm9nuP2DevRhRsGXduwHREKETg7sixpZwp3kQC1eMN+nl/9CiXdZx13zOVsbN17CSQacxcJEL99Zz13v7qyYfuWuctZWXl8sAPfrWktAUzhLhIgZi3Zzlur9hze4ag4YdvRKaM7oCLxJYW7SIBwdVmGK+HThm2H62Cj7e4YfD9X97u6o8oSH1G4iwSI8JQFhHd7D2stSzYXYlwljba7IHMkxmhcJtDpA1WRTm578XYqag8PwVS6PTy6ZA6umLXHtb2x1+8YmDiwI8sTH1G4i3Ryk96cdNR2bnEBOx0v4upyfNshCdkdVJX4moZlRALMJ7lLGt1flT+ZASmaQyZYKNxFAsyf1zzS8NhTlQKAtzYG98EzyUyM8lVZ0sE0LCMSoCLcIxjeZTJf793AjEvP4dwpZ+Fw6IPUYKFwFwlA3tpoenvv5LlrdT97sNKwjEgnVuOpOcERS0y4+m7BTOEu0omV1DR+L7utjSVa4R7UFO4incxHuz5i6AtDOVB1gNKa0uOOW08oVXuvZHRWog+qE3+hX+0inczctfMAeGLpXC7s/b2jjg2JG8O4rnfQPTuJS4d090V54ieaFe7GmEuAJwEnMMta+2gjba4BHgYs8I219vo2rFMkqK3cv5LIkEj6J/SnuKJu8Y03dz7Pol0LsF4XxuEG4JXLj19CT4JTk+FujHECTwPjgTxguTFmobV2/RFt+gL3A2dbaw8aY7q2V8EiweimRTcBsGbqGrz28KIa1bYYT1UGIZE7fFSZ+KvmjLmPArZYa7dZa2uAV4HJx7T5EfC0tfYggLV2f9uWKRK8rD28BuqlT35G7oGyo4+74zq6JOkEmjMs0wPIPWI7DzjjmDb9AIwxn1M3dPOwtfafbVKhSJA7WH146t5v95YQmVl81IJ4p/fM5L5zZoCp7vjixG81p+fe2Ffa7DHbIUBfYCxwHTDLGHPctEXGmNuNMTnGmJyCgoKW1ioSlPaW72147IzcgjN8L97yvvyg7w8AODMzhSHJfRmSNMRXJYofak645wE9j9hOA/Y00uYta63bWrsd2Ehd2B/FWjvTWpttrc1OTk5ubc0iQSW/LL/hsSuubhm9qsKxdIvqBoDb6/ZJXeLfmhPuy4G+xphMY0woMAVYeEybN4HzAYwxSdQN02xry0JFgtWGou0Nj50RO/FU9sRT0Zsp/adwbo9zuX6AbkyT4zUZ7tbaWuAu4H3gW2C+tXadMeYRY8x3E0m/DxQZY9YDi4FfWWuL2qtokWDyyc5lDY8dYYV4a5IAiA+P53/H/S/JkfpXsByvWfe5W2vfA947Zt9DRzy2wC/q/4hIG8kvz2djyXK81Uk4wgoB8Nbom6fSNE0/IOLHHs95HC+1VO2f2LDPU5nmw4qks9D0AyJ+aPO+UuZ88xqL9i4i2jMcp3convpjnsoMztS8MdIEhbuIH7rrla/ZE/8kAEUHE0iPDuP20f/J5oObuf3KiZrOV5qkvyEifigi7PA87dYdR3RMCNf0v8aHFUlnozF3ET8UFn54nvba0sG4PV4fViOdkcJdxA8drNkHQPn2O7GeGCprPE08Q+RoCncRH/lq71c8vuLxhu0DVQfIL8+nqLKIveHPAGDddbN4lNfU+qRG6bw05i7iI7f96zYAfjT0R8SExnD9u9ezu2w3SaEZDW0uH9qff6zaQ2iI+mHSMgp3ER/bfHAzQ5KGsLtsNwCFNTtwlw7iioxb+d33R9C7azQXD9aqStIyCncRH4kJjaG0ppQlu1bz6zdzIRy87hgcrlKq8y8nY2hvjDHcdcFxc/CJNEnhLuJjX+atZe2+XkT2gqq9V+GpzABvGNW1ukNGWk8DeSI+UOGuoLSmFIA9FZswIcUAWHc8eMMAiApT30taT397RHxgf0XdSpTdo7qTX76diB510/p665fMe2DCAG46s5fP6pPOTz13kQ62rmgdOfnfADAi4dyjD9q6XvtNZ2bgcurHU1pPPXeRDjblnSkNj//+WRJRGRBGEod2jwfgx+dlEe5ynuDZIs2jcBfpQDWeI+aMsQ68lWmUb7ubq08/nX0hHs7rn8w12T1PcgaR5lG4i3SQjzbs46WclYd31HYBnHirU8hK6sJDEzXGLm1Hg3oiHeR//rWJT7Zuadju4kppeKwvKUlbU89dpIMkxYRiyg41bHeP7EFkt2jCQpwkx4T5sDIJRAp3kQ6ypepdInr8o2H74n6DuPnKc0/yDJHWU7iLdJCSkC8aHk8fNZ2LMy7W7Y7SbhTuIu1sf0kVt778LkTsa9h3w8AbfFiRBAOFu0g7mvbCl3xd/RhVtS5cwA0ZD3PxwCxflyVBQOEu0k7Kqmv5eNsaorK24AoDT1U3xqSdx8iuSb4uTYKAwl2kHeQdrCC/uApH6IGGfZ7yPqQnRPqwKgkmCneRNva3r3byH/9YS2JUKI6ww+H+1OQbSYtXuEvHULiLtLGXlu4CoKi8hrCYImJccbx75dvEh8f7uDIJJgp3kTbi8XqwWPaXVOGM2oT1hOMIPUB6bE8Fu3Q4hbtIG3nw8wc5VFVMUfklxPZ/ldqaWJzOanrFnunr0iQIKdxF2sjqgtXsLtuNMzoL66jAGV4BQN94rYEqHU9fjxNpA26vmz1le/BYD2FdF+E0df0mh43g6n5X+7g6CUbquYucovkb51NYWUitrQXAGbaf7OSxfL3NMjhpIHFhcT6uUIJRs8LdGHMJ8CTgBGZZax89QburgNeB0621OW1WpYifsNayaPsixvUaR6gzlMLKQh5d9ihur/uodr887T4iTo8nLsLlo0ol2DU5LGOMcQJPA5cCg4DrjDGDGmkXA/wM+KqtixTxF0v3rOC+z+5j3po3APjZu38+KtjLt99F2ebp9EvqQUZSFPFRob4qVYJcc8bcRwFbrLXbrLU1wKvA5Eba/QZ4DKhqw/pE/Mq/tqwAYP7axXyw40NWl72JrcwEwHpD8Vb1wNZ2wekwvixTpFnh3gPIPWI7r35fA2PMSKCntfadk53IGHO7MSbHGJNTUFDQ4mJFfG190bcA7KlZzX2fTcdb1YOyXVPxVCcT7egGKNTFPzRnzL2xv6224aAxDuAJ4OamTmStnQnMBMjOzrZNNBfxO7nlm7HWgXFWUOMxVO25mjF9ehIaeQfTzs0g6oJ+eKz+aovvNSfc84Ajl2NPA/YcsR0DDAE+NsYAdAcWGmMm6UNVCRQHKyrZXVpIqSePOG82Jc5luEuG4ajtxnM3nUZYyChflyhylOaE+3KgrzEmE9gNTAGu/+6gtbYYaJjD1BjzMXCvgl0CxeKN+7nnX7/FE/MxGEv/6NFkJF3E85ugf9e6NVBF/E2TY+7W2lrgLuB94FtgvrV2nTHmEWPMpPYuUMTXHl64Dm/kGqwNwXpDOK37cO4efSUuYhmcqnvYxT816z53a+17wHvH7HvoBG3HnnpZIv6hvLqWXSW7iO5aSC/v9azb3I/vjelNXKSLudNO1/zs4rf0DVWRk9i8v4yQ6M0A/PLcyfzNlDO8Z11v/azeWlFJ/JfCXeQkNuaXEBK1kZTINC7oM4gL+vi6IpHm0cRhIiexbu8BnFHbGJN2tq9LEWkR9dxFGrGvfB8Lty5k5X4HxlXDOWnn+LokkRZRuEtQs9byzrZ3GJM2pmH2xl/MX8WXRa9RFvkOkIjByajuuo9dOhcNy0hQ23BgAw8seYCZq2cCUOvx8v7afA55ttU1cBXRM2IwkS7dFSOdi8JdgtqneZ8C8M62d3B73WzIL6W8xkN8/D5SIzMAuGLAhT6sUKR1NCwjQe2z3Z8R7gznQNUBvtj9Bdt2pWNCSiitLeInI28lu1s2vbv09nWZIi2mcJegdbDqIKsLVnPb0Nt4ef18frX4NzhsFAkpWdQAgxIHMTBxoK/LFGkVhbsElZpaL68s28Vbq3Zz2dn5WCxnp4xhzpJd1EZ/irWlOKK3YTAMTFCwS+elcJegcvPzy/hiaxEApbHvkhCewJbceA7tOZ+x/a/h010ricl8hoy4XvoQVTo1hbsEjYPlNXyxtYg7zutNfvk+PihbwTWZ1zP78x0MTIll9tTTWbQ2DUdUJtFh4b4uV+SUKNwlaKzeXQzAmL5JfLhvEWy2LPgknUMlZfzl+pE4HYaJw1KBVN8WKtIGFO4SNL7JPYQx0D8lkv/4eiFdGEpBRRf+dO2w+lCXzsztdpOXl0dVVWAs4xweHk5aWhoul6tVz1e4S9D4JvcQvZOjeXnTbAorC3n8vBkMu3I03WI1BBMI8vLyiImJISMjg/pV4Totay1FRUXk5eWRmZnZqnPoS0wSFIqri1lZkENC9xXMXD2Ty/tczriM8xTsAaSqqorExMROH+wAxhgSExNP6V8h6rlLwLPWcucHd+PuuoJv3TA4cTAPjn4wIEJAjhZI1/RU34vCXQLSzqJy7nltFcN7dqFbt218U7iC6sLzmTFuElcMOoswZ5ivSxRpVwp3CUhvrd7MNwUrWVcQizNlLoZk7IHxXDX4fC1oLUFB4S6dUoW7Aq/1Eh0afdT+vNI8fvHxL/j2wLfUz/sFwPDQexgxpp+CXTpcTU0NbrebqKioDn1dhbt0OrXeWqb+cyqVtZX8fdLfjxpi+dPXf2JHyQ5CS75Pv/j+XDs6HoDJvScH1His+L9vv/2WWbNmsWDBAhYsWMDIkSM79PUV7tLpvLbxNTYc2ADAC+te4PZhtwOwvmg97+94nxv7T+OZNf24cMRALu+T5ctSxUd+/fY61u8padNzDkqNZcZlg0/apry8nPnz5zN79mystdxyyy2sXr2amJiYNq2lORTu0qkUVRbx9MqnOSv1LCJDInlu9XNclnUZKdEpPLXyKeLC4ugfMQnYwMj0Lr4uV4JMSkoKw4YNY9asWQwYMMCntSjcpVN5auVTVNZWct+o+wh3hrNk9xJ++ckviXRF8tXer/jlab9kY56bEIdhcGqcr8sVH2mqh91e3njjDWbPns0VV1zBddddx9SpU+nVq5dPatGXmKTTWLV/FQs2L+DGQTeSFZdFanQqdwy/g7WFazlUdYhpQ6Zx3cDrWLXrEANTYgl36cNT6VgXXXQRr732GkuWLCEuLo7Jkyczbtw4duzY0eG1qOcunUKNp4aHv3iYbpEpXNNnGtZajDFMGzKNGwfdCDaE3AMVYENYnXeIK77Xw9clSxBLTEzk7rvv5u6772bZsmU4nR3f0VC4S6cwe+1sthZvpTrvFs5d8QWhIQ5S4sJJjYvAGFix8yDVtV5CQxzU1HoZ0TPe1yWLADBq1CifvK7CXfzetkPbeG71c6S5zmRrxUAe/H5/9pdWs+dQJXuLq6iu9XDdqHQGpcSyfm8Juw5UcH7/ZF+XLeJTCnfxa4WVhfz8458T7oxgx6bxXDY8ldvO1e2NIk3RB6ritworC5n2/jTyy/MZn3QflVWR3HJ2hq/LEukUFO7ilwoqCrj1/VvJL8/nz+c/zQdfR3NGZgJDeuj2RpHmaFa4G2MuMcZsNMZsMcZMb+T4L4wx640xq40xHxpjfHNjp3RKFe4KrLUN29sObeOG925gb/lenr7waQ4UpbH7UCXTzmndogUiwajJMXdjjBN4GhgP5AHLjTELrbXrj2i2Esi21lYYY34CPAZc2x4FS2DZemgrVy28irSYNCZkTSArLotff/lrQh2hzL1kLlmx/Znw0mdkJEYybmA3X5cr0mk05wPVUcAWa+02AGPMq8BkoCHcrbWLj2i/FLixLYuUwPXOtnewWJIiknhm1TNYLBmxGTw7/ll6RPfgv95dz7bCcv522xk4HZr4S6S5mhPuPYDcI7bzgDNO0v5WYNGpFCXBwVrLou2LGJ0yml+N+G9eWr6aT3Yt46xu5xAT0pUVOw8wa8l2bjgjnbP7JPm6XJFW8ecpfxvrLtlG9mGMuRHIBs47wfHbgdsB0tPTm1miBKo1hWvYXbab2qJxXPjhJzgMDEw5jb9+vI9Xv1pMZKiT1LgI7p8w0NelirRYZ5jyNw/oecR2GrDn2EbGmHHAfwDnWWurGzuRtXYmMBMgOzu70V8QEhy8XstjS17Fep2UFPXngQkDuHxED7rGhrN2dzGP/98mPt1UwNxbRhEdpq9jSAstmg75a9r2nN2HwqWPnrRJU1P+3nPPPSxevPi4502ZMoXp04+7V+WUNOenZjnQ1xiTCewGpgDXH9nAGDMS+CtwibV2f5tWKAFnX0kVP3/ta1abj0lyDefNn11MfFRow/EhPeKYc/PpVLk9mvxLOpWmpvx94oknOqyWJsPdWltrjLkLeB9wAnOsteuMMY8AOdbahcAfgWjg9frVbnZZaye1Y93SSa3OO8SP5uVQykacPUq5f8x1RwX7kRTs0mpN9LDbS1NT/vpbzx1r7XvAe8fse+iIx+PatCoJSG9/s4d7X/+GpOgwLj59L5/nRzAmbYyvyxJpMxdddBEXXXQRRUVFvPTSS0yePJmkpCRmzZpFRkaGf/XcRVqqsLKQeevm4bEeJvWeRL/4fvzpg808+eFmTs+I5y+DO4SMAAANiUlEQVTXD+eq92YwtudYIl2Rvi5XpM1pyl8JKBXuCl5Y9wJz182l2lONMYZ56+cR68hk/55hnDM8jTGD9vL4qrc4VH2ICZkTfF2ySLvTlL/il+atm0dhVSHnpJ7DyK4jcTldx7XJLc1l8a7FzFk7h6KqIsb3Gs/d37ubMBPFjxY8x9aKxYR3f4tvauCbVRATGsOo7qM4K/UsH7wjkeCgcJcT+r+d/8cfc/4IwPNrnycyJJIzUs7gnB7nEBcWx9K9S/lyz5fsLtsNwGndTuOpC55iWPIwiivd/GheDmt3DOPhy67j3EFevNZL96juRIdG+/JtiQQFhbs0am/ZXmZ8MYMhiUN4dvyzrNi3giW7l7Bk9xIW59Z92h/liiYjchgJ4ePI29OTlTu7MOWLPbg9ebg9FpfT8OSUkUwanurjdyMSfBTucpxaby3TP5uO13p5bMxjxIXFcUH6BVyQfgFer5fnli5l4ZrtbNgYS77XQVSok9FZiaRmRhAa4qj743Qwpl8yp/XScncivqBwl+PMXD2Tr/d/ze/P/T09Yw9/OTm/uIr7F6xm8caD9O/WkzvO68qYvsmMTI8nNERLA4j4E4W7HCUnP4e/rv4rk3pPYmLWRKBugq83VuTxyDvrcXu8zLhsEFPPzMChWRpF/JbCXRoUVxcz/bPppEWn8cAZDwB1vfUH/rGGjzbsZ1RGAo9dNYyMpI6d3U5EWk7hLkBd73zGFzMoqiripQkvERkSyRsr8vj12+twe7w8NHEQN5+l3rrIyRw8eJD4eP/4nEnhLtR4api9ZjYf7vqQe7PvJTGkN7e+kMNHG/ZzekY8j101nEz11kWalJ2dzRlnnMFtt93G+eefT/1cWz6hcA9i1Z5qFmxewOw1s9lXsY8L0y8ksvJ8xj/xiXrr0qn9Ydkf2HBgQ5uec0DCAO4bdd9J22zatIlFixbxl7/8hTvvvJMf/vCH3HzzzaSmdvztwAr3IFRZW8nfN/2dOWvnUFBZwIjkkdw2YDrvr4jlVxvWqLcu0kpOp5OJEycyceJECgoKuP/++0lPT+eLL77o8GkIFO5BZF9ZIc+smM+i3Feo8Bwi2vYn6uC1fL6hB5/ZasJdRfxnfW9d65VKZ9ZUD7s9FRcX89prr/H888/jcrmYPXs2w4YN6/A6FO4B7FDVIXL25bA8fzmf7/6KnaVbAagt64spvo6E6KFkdY8mc0gUvZOjyM5IoEeXCB9XLdJ53XjjjXz55ZdcffXVzJs3j759+/qsFoV7ALDWUu4up6CygG3F28jJz2FZ/jI2HdwEgMuEUV2eTkjNBH4yagKXDzqDbrFhPv2wRyQQXXPNNcydO5eQEN9Hq+8rkCbVeGpYsW8F+yv2U1BZQGFlIQUV9f+t366srWxoH+4MZ0TXEfx46J2s2JjA4m/CGJ3VlSdvGUm32HAfvhORwDZpkv8sQKdw92OlNaXM3zifl759icLKwob9Ua4okiOSSYpIYkjiEJIikxq202LSGJw4mM37Kvm3l1eyo6ice8b1464L+mgcXSSIKNz9UEFFAS9++yKvb3ydMncZo1NGM+PMGWTFZZEUkXTS1Yustby4dCe/ffdb4iNdvPyj0YzOSuzA6kXEHyjc/ciO4h3MXTeXhVsX4rEexvcazy1DbmFw4uAmn+vxWrYXlvPf72/kn+vyGds/mf+5ejiJ0WEdULmI+BuFux9YW7iWOWvn8MHOD3A5XFzR5wpuHnzzUTMyHqnK7WFDfinr95Swbk8x6/eWsGFvKZVuDyEOwwMTBnDbOVn68pFIEFO4d5C9xZV8trmQz7cUsmz7AWo8XkKjN1MT/SE1rk04bCTdmUAvx8WU5CXw3P5iIkLLiHA5iQx14vHChvwS1u8pYWtBGV5bd96YsBAGpsYyZVRPBqXEMiozgV6J+vKRSLBTuLeTkio3S7cW8fmWQj7bUsi2gnJwVJMQV0zvnsXssR9Q4t1JKPGkeq8hqvpsatwuttZ4qKwppNLtoaLGQ02tt+GcKXHhDEqJ5dIh3RmUGsvg1DjS4iN0S6OIHEfh3kbcHi+rcg+xeNNuPtn6LZsP7gBXAa7wImITD9GtWyEVnoO4gQ0eyIzL5N7BjzAxa2Kji05/x+O1VLo9eK0lNvzE7UREjqRwbwW3x01uaS5Lczfy+c4NbCjcxr7KPKyrAIerGCIhrP6GlsTwRHrF9qJX7BDSY9PrH/eiT5c+OEzTqxc5HYboMF0mkc5AU/52AhXuCvLK8sgtzSWvNI/ckly2HNzJtuIdHKzZB9iGtsZGkhCTSmZcNiNT+tI/MasuyGN6ER0a7bs3ISIdSlP++gFrLUVVRXXBXR/gu0p3saM4l10luZS4Dxzd3hOOtyYRr7srod4h9EvMZHRafy4dMIzB3VN89C5EpDH5v/sd1d+27ZS/YQMH0P2BB07apqkpf++55x4WL1583POmTJnC9OnT27TegA53t9fN3rK95JbmHu6Bl+aysySXvLI8qj2Hv7KPNeCJpbY6Aa87C1uTjalNpGtkD3p3SadP165kJkczPK0Lg1JidZuhiBynqSl/n3jiiQ6rpdOHe2lNaUNo55bmNgyl5Jbkkl+ej5fDd5sYGwK1ibir4vG6v4e3JgGvO5HksFQy49PondSFzKRospKiyEyKIi0+ghBn0+PiIuJfmupht6eTTfmrnvtJfJb3GW9ve7sh0A9VHzrqeIiNxtYmUl2RjMc9AG9NArYmgVhXdzLjU8hKiiGzd1RdgCdH0SshiohQp4/ejYgEkqam/FXP/SQ+3rqJj3bkYN0JVFb0p7YqAa87AW9NAuEmmfSEJDKToshKjyKjvgeemRRFl8hQX5cuIgGu0035a4y5BHgScAKzrLWPHnM8DJgHnAYUAddaa3e0bal1+kaMJ7awd13Pu3cUmUnRdWGeHEXXGM1RLiK+06mm/DXGOIGngfFAHrDcGLPQWrv+iGa3AgettX2MMVOAPwDXtkfBU0alM2VUenucWkQkYDTn08JRwBZr7TZrbQ3wKjD5mDaTgRfqH78BXGjUhRYR8ZnmhHsPIPeI7bz6fY22sdbWAsWAJhEXkQ5lrW26USdxqu+lOeHeWA/82FdtThuMMbcbY3KMMTkFBQXNqU9EpFnCw8MpKioKiIC31lJUVER4eOuXxWzOB6p5wJETi6cBe07QJs8YEwLEAQeOaYO1diYwEyA7O7vzXwER8RtpaWnk5eURKB3H8PBw0tLSWv385oT7cqCvMSYT2A1MAa4/ps1CYCrwJXAV8JENhF+fItJpuFwuMjMzfV2G32gy3K21tcaYu4D3qbsVco61dp0x5hEgx1q7EJgNvGiM2UJdj31KexYtIiIn16z73K217wHvHbPvoSMeVwFXt21pIiLSWpo4RUQkABlfDY0bYwqAnSdpEkfdLZUtPX6q+5OAwpO8bntq6j2313ma27611+Rkxxrb39g+X10XX12TljynI35W/OmaQNtcF3+8Jic79t3+Xtba5CYrsNb65R9gZmuOn+p+6j5H8Mv33F7naW771l6Tll6XE+zzyXXx1TXpiOvSWa9JW10Xf7wmrbleJ/rjz8Myb7fyeFvt94W2qqWl52lu+9Zek5Mda2y/rknLntMRPyv+dE2gberxx2tysmMtqtdnwzL+yhiTY63N9nUdcjRdF/+ja+Lf/Lnn7iszfV2ANErXxf/omvgx9dxFRAKQeu4iIgFI4S4iEoAU7iIiAcj3C/11IsaYQcDD1C0l+KG19g3fViTGmHTgL9R9mWaTPWYJSPENY8y5wA3UZcwga+1ZPi4p6ARNz90YM8cYs98Ys/aY/ZcYYzYaY7YYY6Y3cZpLgT9ba38C3NRuxQaJNrom/YB3rbXTgEHtVmwQaYvrYq39zFp7B/AOh1dpkw4UNHfLGGPGAGXAPGvtkPp9TmATR6wPC1xH3eyXvz/mFNPq/zsDqADOstae3QGlB6w2uiYe6pZ2tMCL1trnO6b6wNUW18Vau7/+efOB26y1JR1UvtQLmmEZa+2nxpiMY3Y3rA8LYIx5FZhsrf09MPEEp7qz/i/6gvaqNVi0xTUxxtwLzKg/1xuAwv0UtdXPSv2QWbGC3TeCZljmBJqzPmwDY0yGMWYmMA/4YzvXFqxadE2AfwI/M8Y8C+xox7qCXUuvC8Ct6JetzwRNz/0EmrX2a8MBa3cAt7dbNQItvyZrqVv9S9pXi64LgLV2RjvVIs0Q7D335qwPKx1L18Q/6bp0MsEe7g3rwxpjQqlbHnChj2sKdrom/knXpZMJmnA3xrxC3QLe/Y0xecaYW621tcB368N+C8y31q7zZZ3BRNfEP+m6BIaguRVSRCSYBE3PXUQkmCjcRUQCkMJdRCQAKdxFRAKQwl1EJAAp3EVEApDCXeQEjDEP109MJtLpKNxFRAKQwl3kCMaY/6hfkOIDoL+v6xFprWCfFVKkgTHmNOrmTBlJ3c/G18AKnxYl0koKd5HDzgX+Ya2tADDGaGIs6bQ0LCNyNE22JAFB4S5y2KfAFcaYCGNMDHCZrwsSaS0Ny4jUs9Z+bYx5DVgF7AQ+83FJIq2mKX9FRAKQhmVERAKQwl1EJAAp3EVEApDCXUQkACncRUQCkMJdRCQAKdxFRAKQwl1EJAD9P9T+Y0qPruBmAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "ax = df.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<\")\n", - "df2.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<=\", ax=ax)\n", - "df3.plot(x=\"d\", y=\"ratio\", logx=True, label=\">\", ax=ax)\n", - "df4.plot(x=\"d\", y=\"ratio\", logx=True, label=\">=\", ax=ax)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "90 5.357827181917685e-08 : 999 999\n", - "190 1.1310968495159557e-07 : 1019 1019\n", - "290 1.726410980840143e-07 : 1013 1013\n", - "390 2.32172511216433e-07 : 994 994\n", - "490 2.9170392434885173e-07 : 1012 1012\n", - "590 3.5123533748127045e-07 : 984 984\n", - "690 4.1076675061368917e-07 : 1024 1024\n", - "790 4.702981637461079e-07 : 982 982\n", - "890 5.298295768785266e-07 : 966 966\n", - "990 5.893609900109453e-07 : 1001 1001\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dratiototal
05.953141e-101.0976
11.190628e-091.0983
21.785942e-091.01024
32.381257e-091.0966
42.976571e-091.01016
\n", - "
" - ], - "text/plain": [ - " d ratio total\n", - "0 5.953141e-10 1.0 976\n", - "1 1.190628e-09 1.0 983\n", - "2 1.785942e-09 1.0 1024\n", - "3 2.381257e-09 1.0 966\n", - "4 2.976571e-09 1.0 1016" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def inf_strict_neg(x, y):\n", - " f1 = (-x) >= (-y)\n", - " f2 = (-numpy.float32(x)) >= (-numpy.float32(y))\n", - " return f1, f2\n", - "\n", - "dfn = count_events(inf_strict_neg)\n", - "dfn.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "ax = df.plot(x=\"d\", y=\"ratio\", logx=True, label=\"<\")\n", - "dfn.plot(x=\"d\", y=\"ratio\", logx=True, label=\"-1 x >=\", ax=ax)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Conclusion\n", - "\n", - "The result is expected. As soon as two float are rounded to the same value, the strict inequality no longer holds. However, if you need to write a code which has to handle double and float (in a template for example), you should use not strict inequalities. It is easier to compare the results but you should read some article like [Is < faster than <=?](https://stackoverflow.com/questions/12135518/is-faster-than). According to [Processing costs of non-strict\n", - "versus strict comparison](http://www.crcummins.com/CRCProcessing.pdf), ``<`` is 5-10% faster than ``<=``." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/_doc/notebooks/python/gil_example.ipynb b/_doc/notebooks/python/gil_example.ipynb deleted file mode 100644 index 9a42fb80..00000000 --- a/_doc/notebooks/python/gil_example.ipynb +++ /dev/null @@ -1,320 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Le GIL\n", - "\n", - "Le GIL ou [Global Interpreter Lock](https://en.wikipedia.org/wiki/Global_interpreter_lock) est un verrou unique auquel l'interpr\u00e9teur Python fait appel constamment pour prot\u00e9ger tous les objets qu'il manipule contre des acc\u00e8s concurrentiels." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Deux listes en parall\u00e8lle\n", - "\n", - "On mesure le temps n\u00e9cessaire pour cr\u00e9er deux liste et comparer ce temps avec celui que cela prendrait en parall\u00e8le." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10.4 ms \u00b1 1.87 ms per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n" - ] - } - ], - "source": [ - "def create_list(n):\n", - " res = []\n", - " for i in range(n):\n", - " res.append(i)\n", - " return res\n", - "\n", - "%timeit create_list(100000)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "En parall\u00e8le avec le module [concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html) et deux appels \u00e0 la m\u00eame fonction." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "54.7 ms \u00b1 4.94 ms per loop (mean \u00b1 std. dev. of 7 runs, 10 loops each)\n" - ] - } - ], - "source": [ - "from concurrent.futures import ThreadPoolExecutor\n", - "\n", - "def run2(nb):\n", - " with ThreadPoolExecutor(max_workers=2) as executor:\n", - " for res in executor.map(create_list, [nb, nb+1]):\n", - " pass\n", - " \n", - "%timeit run2(100000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "C'est plus long que si les calculs \u00e9taient lanc\u00e9s les uns apr\u00e8s les autres. Ce temps est perdu \u00e0 synchroniser les deux threads bien que les deux boucles n'aient rien \u00e0 \u00e9changer. Chaque thread passe son temps \u00e0 attendre que l'autre ait termin\u00e9 de mettre \u00e0 jour sa liste et le *GIL* impose que ces mises \u00e0 jour aient lieu une apr\u00e8s l'autre." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Un autre sc\u00e9nario\n", - "\n", - "Au lieu de mettre \u00e0 jour une liste, on va lancer un thread qui ne fait rien qu'attendre. Donc le *GIL* n'est pas impliqu\u00e9." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "9.36 ms \u00b1 28.3 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n" - ] - } - ], - "source": [ - "import time\n", - "\n", - "def attendre(t=0.009):\n", - " time.sleep(t)\n", - " return None\n", - "\n", - "%timeit attendre()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "12.6 ms \u00b1 43.5 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100 loops each)\n" - ] - } - ], - "source": [ - "def run2(t):\n", - " with ThreadPoolExecutor(max_workers=2) as executor:\n", - " for res in executor.map(attendre, [t, t+0.001]):\n", - " pass\n", - " \n", - "%timeit run2(0.009)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "Les deux attentes se font en parall\u00e8le car le temps moyen est significativement inf\u00e9rieur \u00e0 la somme des deux attentes." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.1" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} \ No newline at end of file diff --git a/_doc/notebooks/python/hypercube.ipynb b/_doc/notebooks/python/hypercube.ipynb deleted file mode 100644 index 3548ca7c..00000000 --- a/_doc/notebooks/python/hypercube.ipynb +++ /dev/null @@ -1,820 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Hypercube et autres exercices\n", - "\n", - "Exercices autour de tableaux en plusieurs dimensions et autres exercices." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q1 - triple r\u00e9cursivit\u00e9\n", - "\n", - "R\u00e9\u00e9crire la fonction ``u`` de fa\u00e7on \u00e0 ce qu'elle ne soit plus r\u00e9currente." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "9" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def u(n):\n", - " if n <= 2:\n", - " return 1\n", - " else: \n", - " return u(n-1) + u(n-2) + u(n-3)\n", - "\n", - "u(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le probl\u00e8me de cette \u00e9criture est que la fonction est triplement r\u00e9cursive et que son co\u00fbt est aussi grand que la fonction elle-m\u00eame. V\u00e9rifions." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(9, [5, 4, 3, 2, 1, 0, 2, 1, 3, 2, 1, 0, 2])" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "compteur = []\n", - "\n", - "def u_st(n):\n", - " global compteur\n", - " compteur.append(n)\n", - " if n <= 2:\n", - " return 1\n", - " else: \n", - " return u_st(n-1) + u_st(n-2) + u_st(n-3)\n", - "\n", - "u_st(5), compteur" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La seconde liste retourne tous les *n* pour lesquels la fonction ``u_st`` a \u00e9t\u00e9 appel\u00e9e." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "9" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def u_non_recursif(n):\n", - " if n <= 2:\n", - " return 1\n", - " u0 = 1\n", - " u1 = 1\n", - " u2 = 1\n", - " i = 3\n", - " while i <= n:\n", - " u = u0 + u1 + u2\n", - " u0 = u1\n", - " u1 = u2\n", - " u2 = u\n", - " i += 1\n", - " return u\n", - "\n", - "u_non_recursif(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q2 - comparaison de listes\n", - "\n", - "On consid\u00e8re deux listes d'entiers. La premi\u00e8re est inf\u00e9rieure \u00e0 la seconde si l'une des deux conditions suivantes est v\u00e9rifi\u00e9e :\n", - "\n", - "* les $n$ premiers nombres sont \u00e9gaux mais la premi\u00e8re liste ne contient que $n$ \u00e9l\u00e9ments tandis que la seconde est plus longue, \n", - "* les $n$ premiers nombres sont \u00e9gaux mais que le $n+1^{\\text{\u00e8me}}$ de la premi\u00e8re liste est inf\u00e9rieur au $n+1^{\\text{\u00e8me}}$ de la seconde liste\n", - "\n", - "Par cons\u00e9quent, si $l$ est la longueur de la liste la plus courte, comparer ces deux listes d'entiers revient \u00e0 parcourir tous les indices depuis 0 jusqu'\u00e0 $l$ exclu et \u00e0 s'arr\u00eater sur la premi\u00e8re diff\u00e9rence qui d\u00e9termine le r\u00e9sultat. S'il n'y pas de diff\u00e9rence, alors la liste la plus courte est la premi\u00e8re. Il faut \u00e9crire une fonction ``compare_liste(p,q)`` qui impl\u00e9mente cet algorithme." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def compare_liste(p, q):\n", - " i = 0\n", - " while i < len(p) and i < len(q):\n", - " if p [i] < q [i]: \n", - " return -1 # on peut d\u00e9cider\n", - " elif p [i] > q [i]: \n", - " return 1 # on peut d\u00e9cider\n", - " i += 1 # on ne peut pas d\u00e9cider\n", - " # fin de la boucle, il faut d\u00e9cider \u00e0 partir des longueurs des listes\n", - " if len (p) < len (q): \n", - " return -1\n", - " elif len (p) > len (q): \n", - " return 1\n", - " else : \n", - " return 0\n", - " \n", - "compare_liste([0, 1], [0, 1, 2])" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "compare_liste([0, 1, 3], [0, 1, 2])" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "compare_liste([0, 1, 2], [0, 1, 2])" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "compare_liste([0, 1, 2, 4], [0, 1, 2])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q3 - pr\u00e9cision des calculs\n", - "\n", - "On cherche \u00e0 calculer la somme des termes d'une suite g\u00e9om\u00e9triques de raison~$\\frac{1}{2}$. On d\u00e9finit $r=\\frac{1}{2}$, on cherche donc \u00e0 calculer $\\sum_{i=0}^{\\infty} r^i$ qui une somme convergente mais infinie. Le programme suivant permet d'en calculer une valeur approch\u00e9e. Il retourne, outre le r\u00e9sultat, le nombre d'it\u00e9rations qui ont permis d'estimer le r\u00e9sultat." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(2.0, 1075)\n" - ] - } - ], - "source": [ - "def suite_geometrique_1(r):\n", - " x = 1.0\n", - " y = 0.0\n", - " n = 0\n", - " while x > 0:\n", - " y += x\n", - " x *= r\n", - " n += 1\n", - " return y, n\n", - " \n", - "print(suite_geometrique_1(0.5))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Un informaticien plus exp\u00e9riment\u00e9 a \u00e9crit le programme suivant qui retourne le m\u00eame r\u00e9sultat mais avec un nombre d'it\u00e9rations beaucoup plus petit." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(2.0, 55)\n" - ] - } - ], - "source": [ - "def suite_geometrique_2(r):\n", - " x = 1.0\n", - " y = 0.0\n", - " n = 0\n", - " yold = y + 1\n", - " while abs (yold - y) > 0:\n", - " yold = y\n", - " y += x\n", - " x *= r\n", - " n += 1\n", - " return y,n\n", - " \n", - "print(suite_geometrique_2(0.5))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expliquez pourquoi le second programme est plus rapide tout en retournant le m\u00eame r\u00e9sultat. Rep\u00e8re num\u00e9rique : $2^{-55} \\sim 2,8.10^{-17}$." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Tout d'abord le second programme est plus rapide car il effectue moins d'it\u00e9rations, 55 au lieu de 1075. Maintenant, il s'agit de savoir pourquoi le second programme retourne le m\u00eame r\u00e9sultat que le premier mais plus rapidement. L'ordinateur ne peut pas calculer num\u00e9riquement une somme infinie, il s'agit toujours d'une valeur approch\u00e9e. L'approximation d\u00e9pend de la pr\u00e9cision des calculs, environ 14 chiffres pour *python*. Dans le premier programme, on s'arr\u00eate lorsque $r^n$ devient nul, autrement dit, on s'arr\u00eate lorsque $x$ est si petit que *python* ne peut plus le repr\u00e9senter autrement que par~0, c'est-\u00e0-dire qu'il n'est pas possible de repr\u00e9senter un nombre dans l'intervalle $[0,2^{-1055}]$.\n", - "\n", - "Toutefois, il n'est pas indispensable d'aller aussi loin car l'ordinateur n'est de toute fa\u00e7on pas capable d'ajouter un nombre aussi petit \u00e0 un nombre plus grand que~1. Par exemple, $1 + 10^{17} = 1,000\\, 000\\, 000\\, 000\\, 000\\, 01$. Comme la pr\u00e9cision des calculs n'est que de 15 chiffres, pour *python*, $1 + 10^{17} = 1$. Le second programme s'inspire de cette remarque : le calcul s'arr\u00eate lorsque le r\u00e9sultat de la somme n'\u00e9volue plus car il additionne des nombres trop petits \u00e0 un nombre trop grand. L'id\u00e9e est donc de comparer la somme d'une it\u00e9ration \u00e0 l'autre et de s'arr\u00eater lorsqu'elle n'\u00e9volue plus.\n", - "\n", - "Ce raisonnement n'est pas toujours applicable. Il est valide dans ce cas car la s\u00e9rie $s_n = \\sum_{i=0}^{n} r^i$ est croissante et positive. Il est valide pour une s\u00e9rie convergente de la forme $s_n = \\sum_{i=0}^{n} u_i$ et une suite $u_n$ de module d\u00e9croissant.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q4 - hypercube\n", - "\n", - "Un chercheur cherche \u00e0 v\u00e9rifier qu'une suite de~0 et de~1 est al\u00e9atoire. Pour cela, il souhaite compter le nombre de s\u00e9quences de $n$ nombres successifs. Par exemple, pour la suite 01100111 et $n=3$, les triplets sont 011, 110, 100, 001, 011, 111. Le triplet 011 appara\u00eet deux fois, les autres une fois. Si la suite est al\u00e9atoire, les occurrences de chaque triplet sont en nombres \u00e9quivalents. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[[[0, 0], [0, 0]], [[0, 0], [0, 0]]]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def hyper_cube_liste(n, m=None):\n", - " if m is None:\n", - " m = [0, 0]\n", - " if n > 1 :\n", - " m[0] = [0,0]\n", - " m[1] = [0,0]\n", - " m[0] = hyper_cube_liste (n-1, m[0])\n", - " m[1] = hyper_cube_liste (n-1, m[1])\n", - " return m\n", - "\n", - "hyper_cube_liste(3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La seconde \u00e0 base de dictionnaire (plus facile \u00e0 manipuler) :" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{(0, 0, 0): 0,\n", - " (0, 0, 1): 0,\n", - " (0, 1, 0): 0,\n", - " (0, 1, 1): 0,\n", - " (1, 0, 0): 0,\n", - " (1, 0, 1): 0,\n", - " (1, 1, 0): 0,\n", - " (1, 1, 1): 0}" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def hyper_cube_dico (n) :\n", - " r = { }\n", - " ind = [ 0 for i in range (0,n) ]\n", - " while ind [0] <= 1 :\n", - " cle = tuple(ind) # conversion d'une liste en tuple\n", - " r[cle] = 0\n", - " ind[-1] += 1\n", - " k = len(ind)-1\n", - " while ind[k] == 2 and k > 0:\n", - " ind[k] = 0\n", - " ind[k-1] += 1\n", - " k -= 1\n", - " return r\n", - "\n", - "hyper_cube_dico(3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le chercheur a commenc\u00e9 \u00e0 \u00e9crire son programme :" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "def occurrence(l,n) :\n", - " # d = ....... # choix d'un hyper_cube (n)\n", - " # .....\n", - " # return d\n", - " pass\n", - "\n", - "suite = [ 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1 ]\n", - "h = occurrence(suite, 3)\n", - "h" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Sur quelle structure se porte votre choix (a priori celle avec dictionnaire), compl\u00e9ter la fonction ``occurrence``. " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{(0, 0, 0): 0,\n", - " (0, 0, 1): 0,\n", - " (0, 1, 0): 0,\n", - " (0, 1, 1): 1,\n", - " (1, 0, 0): 0,\n", - " (1, 0, 1): 2,\n", - " (1, 1, 0): 1,\n", - " (1, 1, 1): 0}" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def occurrence(tu, n):\n", - " d = hyper_cube_dico(n)\n", - " for i in range (0, len(tu)-n) :\n", - " cle = tu[i:i+n]\n", - " d[cle] += 1\n", - " return d\n", - "\n", - "occurrence((1, 0, 1, 1, 0, 1, 0), 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Il est m\u00eame possible de se passer de la fonction ``hyper_cube_dico`` :" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{(1, 0, 1): 2, (0, 1, 1): 1, (1, 1, 0): 1}" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def occurrence2(tu, n):\n", - " d = { }\n", - " for i in range (0, len(tu)-n) :\n", - " cle = tu[i:i+n]\n", - " if cle not in d: \n", - " d[cle] = 0\n", - " d [cle] += 1\n", - " return d\n", - "\n", - "occurrence2((1, 0, 1, 1, 0, 1, 0), 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La seule diff\u00e9rence appara\u00eet lorsqu'un n-uplet n'appara\u00eet pas dans la liste. Avec la fonction ``hyper_cube_dico``, ce n-uplet recevra la fr\u00e9quence 0, sans cette fonction, ce n-uplet ne sera pas pr\u00e9sent dans le dictionnaire ``d``. Le m\u00eame programme avec la structure matricielle est plus une curiosit\u00e9 qu'un cas utile. " - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[[[0, 0], [0, 1]], [[0, 2], [1, 0]]]" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def occurrence3(li, n):\n", - " d = hyper_cube_liste(n)\n", - " for i in range (0, len(li)-n) :\n", - " cle = li[i:i+n]\n", - " t = d # \n", - " for k in range (0,n-1) : # point cl\u00e9 de la fonction : \n", - " t = t[cle[k]] # acc\u00e8s \u00e0 un \u00e9l\u00e9ment\n", - " t [cle [ n-1] ] += 1\n", - " return d\n", - "\n", - "occurrence3((1, 0, 1, 1, 0, 1, 0), 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Une autre \u00e9criture..." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[[[0, 0], [0, 1]], [[0, 2], [1, 0]]]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def hyper_cube_liste2(n, m=[0, 0], m2=[0, 0]):\n", - " if n > 1 :\n", - " m[0] = list(m2)\n", - " m[1] = list(m2)\n", - " m[0] = hyper_cube_liste2(n-1, m[0])\n", - " m[1] = hyper_cube_liste2(n-1, m[1])\n", - " return m\n", - "\n", - "def occurrence4(li, n):\n", - " d = hyper_cube_liste2(n) # * remarque voir plus bas\n", - " for i in range (0, len(li)-n) :\n", - " cle = li[i:i+n]\n", - " t = d # \n", - " for k in range (0,n-1) : # point cl\u00e9 de la fonction : \n", - " t = t[cle[k]] # acc\u00e8s \u00e0 un \u00e9l\u00e9ment\n", - " t [cle [ n-1] ] += 1\n", - " return d\n", - "\n", - "occurrence4((1, 0, 1, 1, 0, 1, 0), 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Et si on remplace ``list(m2)`` par ``m2``." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "'int' object is not iterable\n" - ] - } - ], - "source": [ - "def hyper_cube_liste3(n, m=[0, 0], m2=[0, 0]):\n", - " if n > 1 :\n", - " m[0] = m2\n", - " m[1] = m2\n", - " m[0] = hyper_cube_liste3(n-1, m[0])\n", - " m[1] = hyper_cube_liste3(n-1, m[1])\n", - " return m\n", - "\n", - "def occurrence5(li, n):\n", - " d = hyper_cube_liste3(n) # * remarque voir plus bas\n", - " for i in range (0, len(li)-n) :\n", - " cle = li[i:i+n]\n", - " t = d # \n", - " for k in range (0,n-1) : # point cl\u00e9 de la fonction : \n", - " t = t[cle[k]] # acc\u00e8s \u00e0 un \u00e9l\u00e9ment\n", - " t [cle [ n-1] ] += 1\n", - " return d\n", - "\n", - "try:\n", - " occurrence5((1, 0, 1, 1, 0, 1, 0), 3)\n", - "except Exception as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Int\u00e9ressant..." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/_doc/notebooks/python/notebook_template.ipynb b/_doc/notebooks/python/notebook_template.ipynb deleted file mode 100644 index 596499c4..00000000 --- a/_doc/notebooks/python/notebook_template.ipynb +++ /dev/null @@ -1,201 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Premier notebook\n", - "\n", - "Premier notebook et premier menu javascript." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Premier paragraphe" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "### Un sous paragraphe" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.1" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} \ No newline at end of file diff --git a/_doc/notebooks/python/partie_dame.ipynb b/_doc/notebooks/python/partie_dame.ipynb deleted file mode 100644 index b4ebf852..00000000 --- a/_doc/notebooks/python/partie_dame.ipynb +++ /dev/null @@ -1,537 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Parties de dames\n", - "\n", - "Exercice de programmation sur les tableaux." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q1 \n", - "\n", - "Une partie de dames met en jeu quarante pions, vingt noirs, vingt blancs, chacun sur des cases diff\u00e9rentes. L'objectif est de savoir si un pion est en mesure d'en prendre un autre. On ne traitera pas le cas des dames. Chaque pion est d\u00e9fini par :\n", - "\n", - "* deux coordonn\u00e9es enti\u00e8res, chacune comprise entre 1 et 10\n", - "* une couleur, noir ou blanc\n", - "\t\t\n", - "On propose deux repr\u00e9sentations de l'ensemble de pions :\n", - "\n", - "* Un tableau de 40 pions indic\u00e9s de 0 \u00e0 39 inclus, chaque pion \u00e9tant d\u00e9fini par :\n", - " * deux coordonn\u00e9es comprises entre 1 et 10, ou (0,0) si le pion n'est plus sur le damier\n", - "\t* un entier qui vaut 1 pour blanc, 2 pour noir\n", - "* Un tableau d'entiers \u00e0 deux dimensions, chaque case contient :\n", - " * soit 0 s'il n'y a pas de pion\n", - "\t* soit 1 si la case contient un pion blanc\n", - " * soit 2 si la case contient un pion noir\n", - "\n", - "Y a-t-il d'autres repr\u00e9sentations de ces informations~? Si on consid\u00e8re que l'efficacit\u00e9 d'une m\u00e9thode est reli\u00e9e \u00e0 sa vitesse - autrement dit aux co\u00fbts des algorithmes qu'elles utilisent -, parmi ces deux repr\u00e9sentations, quelle est celle qui semble la plus efficace pour savoir si un pion donn\u00e9 du damier est en mesure d'en prendre un autre ?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**r\u00e9ponse**\n", - "\n", - "La seconde repr\u00e9sentation sous forme de tableau \u00e0 deux dimensions est plus pratique pour effectuer les tests de voisinages. Chaque case a quatre voisines aux quatre coins, il est ensuite facile de d\u00e9terminer si ces quatre voisines sont libres ou si elles contiennent un pion. On sait rapidement le contenu d'une case.\n", - "\n", - "Avec la premi\u00e8re repr\u00e9sentation - le tableau des pions - pour savoir s'il existe un pion dans une case voisine, il faut passer en revue tous les pions pour savoir si l'un d'eux occupe ou non cette case. Avec la seconde repr\u00e9sentation - le tableau \u00e0 deux dimensions - on acc\u00e8de directement \u00e0 cette information sans avoir \u00e0 la rechercher. On \u00e9vite une boucle sur les pions avec la seconde repr\u00e9sentation." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q2\n", - "\n", - "Comment repr\u00e9senter un tableau d'entiers \u00e0 deux dimensions en langage python \u00e0 l'aide des types standards qu'il propose, \u00e0 savoir t-uple, liste ou dictionnaire ?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**r\u00e9ponse**\n", - "\n", - "Pour repr\u00e9senter le tableau en deux dimensions, il existe trois solutions :\n", - "\n", - "* Une liste de listes, chaque ligne est repr\u00e9sent\u00e9e par une liste. Toutes ces listes sont elles-m\u00eames assembl\u00e9es dans une liste globale.\n", - "* Une seule liste, il suffit de num\u00e9roter les cases du damier de 0 \u00e0 99, en utilisant comme indice pour la case $(i,j)$ : $k = 10*i+j$. R\u00e9ciproquement, la case d'indice $k$ aura pour coordonn\u00e9es $(k / 10, \\, k \\% 10)$.\n", - "* Un dictionnaire dont la cl\u00e9 est un couple d'entiers." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q3\n", - "\n", - "On cherche \u00e0 \u00e9crire l'algorithme qui permet de savoir si un pion donn\u00e9 est un mesure de prendre un pion. Quels sont les param\u00e8tres d'entr\u00e9es et les r\u00e9sultats de cet algorithme ? " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**r\u00e9ponse**\n", - "\n", - "On d\u00e9sire savoir si le pion de la case $(i,j)$ peut en prendre un autre. On suppose que le tableau \u00e0 deux dimensions est une liste de dix listes appel\u00e9e ``damier``. ``damier[i][j]`` est donc la couleur du pion de la case $(i,j)$, \u00e0 savoir 0 si la case est vide, 1 si le pion est blanc, 2 si le pion est noir. Pour ces deux derniers cas, la couleur des pions de l'adversaire sera donc ``3 - damier[i][j]``. Les entr\u00e9es de la fonctions sont donc les indices ``i``, ``j`` et le damier ``damier``. La sortie est une variable bool\u00e9enne qui indique la possibilit\u00e9 ou non de prendre. On ne souhaite pas d\u00e9placer les pions." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Q4\n", - "\n", - "Il ne reste plus qu'\u00e0 \u00e9crire cet algorithme." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def pion_prendre(i, j, damier):\n", - " c = damier[i][j]\n", - " if c == 0:\n", - " return False # case vide, impossible de prendre\n", - " c = 3 - c # couleur de l'adversaire\n", - "\n", - " if damier[i-1][j-1] == c: # s'il y a un pion adverse en haut \u00e0 gauche\n", - " if damier[i-2][j-2] == 0: # si la case d'apr\u00e8s en diagonale est vide\n", - " return True # on peut prendre\n", - "\n", - " # on r\u00e9p\u00e8te ce test pour les trois autres cases\n", - " if damier[i-1][j+1] == c and damier[i-2][j+2] == 0:\n", - " return True\n", - " if damier[i+1][j-1] == c and damier[i+2][j-2] == 0:\n", - " return True\n", - " if damier[i+1][j+1] == c and damier[i+2][j+2] == 0:\n", - " return True\n", - " \n", - " # si tous les tests ont \u00e9chou\u00e9, on ne peut pas prendre\n", - " return False\n", - "\n", - "damier = [[0, 0, 1, 0, 0],\n", - " [0, 1, 0, 1, 0], \n", - " [0, 0, 2, 0, 2], \n", - " [0, 0, 0, 2, 0],\n", - " [0, 0, 0, 0, 0],\n", - " ]\n", - "\n", - "pion_prendre(2, 2, damier)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Voici une fonction \u00e9quivalente lorsque le damier est un dictionnaire dont la cl\u00e9 est un couple d'entiers." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{(0, 0): 0, (0, 1): 0, (0, 2): 1, (0, 3): 0, (1, 0): 0, (1, 1): 1, (1, 2): 0, (1, 3): 1, (2, 0): 0, (2, 1): 0, (2, 2): 2, (2, 3): 0, (3, 0): 0, (3, 1): 0, (3, 2): 0, (3, 3): 2}\n" - ] - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def pion_prendre_dict(i, j, damier):\n", - " c = damier[(i,j)] # ou encore damier [i,j]\n", - " if c == 0:\n", - " return False # case vide, impossible de prendre\n", - " c = 3 - c # couleur de l'adversaire\n", - "\n", - " # test pour une prise du pion dans les quatre cases voisines\n", - " if damier[i-1,j-1] == c and damier[i-2,j-2] == 0: \n", - " return True\n", - " if damier[i-1,j+1] == c and damier[i-2,j+2] == 0: \n", - " return True\n", - " if damier[i+1,j-1] == c and damier[i+2,j-2] == 0: \n", - " return True\n", - " if damier[i+1,j+1] == c and damier[i+2,j+2] == 0: \n", - " return True\n", - " \n", - " # si tous les tests ont \u00e9chou\u00e9, on ne peut pas prendre\n", - " return False\n", - "\n", - "damier_dict = { (i,j): damier[i][j] for i in range(4) for j in range(4)}\n", - "\n", - "print(damier_dict)\n", - "\n", - "pion_prendre_dict(2, 2, damier_dict)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(0, 4)\n" - ] - } - ], - "source": [ - "try:\n", - " pion_prendre_dict(1, 3, damier_dict)\n", - "except Exception as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cela ne marche pas tr\u00e8s bien, cela laisse supposer que la fonction pr\u00e9c\u00e9dente n'est pas tr\u00e8s fonctionnelle non plus. Il manque le fait de v\u00e9rifier que les coordonn\u00e9es test\u00e9es restent dans l'\u00e9chiquier." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La m\u00eame fonction lorsque le damier est repr\u00e9sent\u00e9 par une seule liste." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0]\n" - ] - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def pion_prendre_list(i,j,damier):\n", - " n = int(len(damier) ** 0.5) # on suppose que le damier est carr\u00e9\n", - " c = damier[n*i+j]\n", - " if c == 0: \n", - " return False # case vide, impossible de prendre\n", - " c = 3 - c # couleur de l'adversaire\n", - "\n", - " # test pour une prise du pion dans les quatre cases voisines\n", - " if damier[n*(i-1)+j-1] == c and damier[n*(i-2)+j-2] == 0: \n", - " return True\n", - " if damier[n*(i-1)+j+1] == c and damier[n*(i-2)+j+2] == 0:\n", - " return True\n", - " if damier[n*(i+1)+j-1] == c and damier[n*(i+2)+j-2] == 0: \n", - " return True\n", - " if damier[n*(i+1)+j+1] == c and damier[n*(i+2)+j+2] == 0: \n", - " return True\n", - " \n", - " return False\n", - "\n", - "damier_list = []\n", - "for row in damier:\n", - " damier_list.extend(row)\n", - " \n", - "print(damier_list)\n", - "\n", - "pion_prendre_list(2, 2, damier_list)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pour ces trois cas, aucun effet de bord n'a \u00e9t\u00e9 envisag\u00e9. Si la case est trop pr\u00e8s d'un des bords, un des indices $i,\\;j,\\;i-1,\\;j-1,\\;i+1,\\;j+1,\\;i-2,\\;j-2,\\;i+2,\\;j+2$ d\u00e9signera une case hors du damier. Le code de la fonction ``pion_prendre`` devra donc v\u00e9rifier que chaque case dont elle v\u00e9rifie le contenu appartient au damier." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def pion_prendre_bord(i, j, damier):\n", - " c = damier[i][j]\n", - " if c == 0:\n", - " return False # case vide, impossible de prendre\n", - " c = 3 - c # couleur de l'adversaire\n", - "\n", - " # on r\u00e9p\u00e8te ce test pour les trois autres cases\n", - " if i >= 2 and j >= 2 and \\\n", - " damier[i-1][j-1] == c and damier[i-2][j-2] == 0:\n", - " return True\n", - " if i >= 2 and j < len(damier)-2 and \\\n", - " damier[i-1][j+1] == c and damier[i-2][j+2] == 0:\n", - " return True\n", - " \n", - " if i < len(damier)-2 and j >= 2 and \\\n", - " damier[i+1][j-1] == c and damier[i+2][j-2] == 0: \n", - " return True\n", - " \n", - " if i < len(damier)-2 and j < len(damier)-2 and \\\n", - " damier [i+1][j+1] == c and damier [i+2][j+2] == 0: \n", - " return True\n", - " \n", - " return False\n", - "\n", - "pion_prendre_bord(2, 2, damier)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pion_prendre_bord(1, 3, damier)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La fonction ``pion_prendre(1, 3, damier)`` fonctionne parce que le langage python accepte indices n\u00e9gatifs : ``damier[-1][-1]`` mais le r\u00e9sultat n'est pas n\u00e9cessairement celui souhait\u00e9." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/_doc/notebooks/python/serialisation_examples.ipynb b/_doc/notebooks/python/serialisation_examples.ipynb deleted file mode 100644 index fd8fce99..00000000 --- a/_doc/notebooks/python/serialisation_examples.ipynb +++ /dev/null @@ -1,1280 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# S\u00e9rialisation\n", - "\n", - "Le notebook explore diff\u00e9rentes fa\u00e7ons de s\u00e9rialiser des donn\u00e9es et leurs limites." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## JSON\n", - "\n", - "Le format [JSON](https://fr.wikipedia.org/wiki/JavaScript_Object_Notation) est le format le plus utilis\u00e9 sur internet notemmant via les [API REST](https://fr.wikipedia.org/wiki/Representational_state_transfer)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Ecriture" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "data = {'records': [{'nom': 'Xavier', 'pr\u00e9nom': 'Xavier', \n", - " 'langages':[{'nom':'C++', 'age':40}, {'nom':'Python', 'age': 20}]}]}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'{\"records\": [{\"nom\": \"Xavier\", \"pr\\\\u00e9nom\": \"Xavier\", \"langages\": [{\"nom\": \"C++\", \"age\": 40}, {\"nom\": \"Python\", \"age\": 20}]}]}'" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from json import dump\n", - "from io import StringIO\n", - "buffer = StringIO()\n", - "res = dump(data, buffer) # 1\n", - "seq = buffer.getvalue()\n", - "seq" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lecture" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'records': [{'nom': 'Xavier',\n", - " 'pr\u00e9nom': 'Xavier',\n", - " 'langages': [{'nom': 'C++', 'age': 40}, {'nom': 'Python', 'age': 20}]}]}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from json import load\n", - "buffer = StringIO(seq)\n", - "read = load(buffer)\n", - "read" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Limite\n", - "\n", - "Les matrices [numpy](http://www.numpy.org/) ne sont pas s\u00e9rialisables facilement." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Object of type ndarray is not JSON serializable\n" - ] - } - ], - "source": [ - "import numpy\n", - "data = {'mat': numpy.array([0, 1])}\n", - "\n", - "buffer = StringIO()\n", - "try:\n", - " dump(data, buffer)\n", - "except Exception as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Les classes ne sont pas s\u00e9rialisables non plus facilement.m" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Object of type A is not JSON serializable\n" - ] - } - ], - "source": [ - "class A:\n", - " def __init__(self, att):\n", - " self.att = att\n", - " \n", - "data = A('e')\n", - "buffer = StringIO()\n", - "try:\n", - " dump(data, buffer)\n", - "except Exception as e:\n", - " print(e) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pour ce faire, il faut indiquer au module [json](https://docs.python.org/3/library/json.html) comment convertir la classe en un ensemble de listes et dictionnaires et la classe [JSONEncoder](https://docs.python.org/3/library/json.html#json.JSONEncoder)." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'{\"classname\": \"A\", \"data\": {\"att\": \"e\"}}'" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from json import JSONEncoder\n", - "class MyEncoder(JSONEncoder):\n", - " def default(self, o):\n", - " return {'classname': o.__class__.__name__, 'data': o.__dict__}\n", - " \n", - "data = A('e')\n", - "buffer = StringIO()\n", - "res = dump(data, buffer, cls=MyEncoder)\n", - "res = buffer.getvalue()\n", - "res" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Et la relecture avec la classe [JSONDecoder](https://docs.python.org/3/library/json.html#json.JSONDecoder)." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "<__main__.A at 0x24ddb4d27f0>" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from json import JSONDecoder\n", - "\n", - "class MyDecoder(JSONDecoder):\n", - " def decode(self, o):\n", - " dec = JSONDecoder.decode(self, o)\n", - " if isinstance(dec, dict) and dec.get('classname') == 'A':\n", - " return A(dec['data']['att'])\n", - " else:\n", - " return dec\n", - " \n", - "buffer = StringIO(res)\n", - "obj = load(buffer, cls=MyDecoder)\n", - "obj" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### S\u00e9rialisation rapide\n", - "\n", - "Le module [json](https://docs.python.org/3/library/json.html) est la librairie standard de Python mais comme la s\u00e9rialisation au format *JSON* est un besoin tr\u00e8s fr\u00e9quent, il existe des alternative plus rapide comme [ujson](https://docs.micropython.org/en/latest/pyboard/library/ujson.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "data = {'records': [{'nom': 'Xavier', 'pr\u00e9nom': 'Xavier', \n", - " 'langages':[{'nom':'C++', 'age':40}, {'nom':'Python', 'age': 20}]}]}" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "28.4 \u00b5s \u00b1 2.46 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 10000 loops each)\n" - ] - } - ], - "source": [ - "%timeit dump(data, StringIO())" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.35 \u00b5s \u00b1 677 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "from ujson import dump as udump\n", - "%timeit udump(data, StringIO())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ces deux lignes mesures l'\u00e9criture au format JSON mais il faut aussi mesurer la lecture." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "8.9 \u00b5s \u00b1 1.21 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "buffer = StringIO()\n", - "dump(data, buffer)\n", - "res = buffer.getvalue()\n", - "%timeit load(StringIO(res))" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.25 \u00b5s \u00b1 243 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "from ujson import load as uload\n", - "%timeit uload(StringIO(res))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On enl\u00e8ve le temps pass\u00e9 dans la creation du buffer." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "735 ns \u00b1 63.4 ns per loop (mean \u00b1 std. dev. of 7 runs, 1000000 loops each)\n" - ] - } - ], - "source": [ - "%timeit StringIO(res)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pickle\n", - "\n", - "Le module [pickle](https://docs.python.org/3/library/pickle.html) effectue la m\u00eame chose mais au format binaire. Celui-ci est propre \u00e0 *Python* et ne peut \u00eatre lu d'autres langages, voire parfois par d'autres versions de .Python*." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Ecriture" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "data = {'records': [{'nom': 'Xavier', 'pr\u00e9nom': 'Xavier', \n", - " 'langages':[{'nom':'C++', 'age':40}, {'nom':'Python', 'age': 20}]}]}" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x03}q\\x00X\\x07\\x00\\x00\\x00recordsq\\x01]q\\x02}q\\x03(X\\x03\\x00\\x00\\x00nomq\\x04X\\x06\\x00\\x00\\x00Xavierq\\x05X\\x07\\x00\\x00\\x00pr\\xc3\\xa9nomq\\x06h\\x05X\\x08\\x00\\x00\\x00langagesq\\x07]q\\x08(}q\\t(h\\x04X\\x03\\x00\\x00\\x00C++q\\nX\\x03\\x00\\x00\\x00ageq\\x0bK(u}q\\x0c(h\\x04X\\x06\\x00\\x00\\x00Pythonq\\rh\\x0bK\\x14ueuas.'" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from pickle import dump\n", - "from io import BytesIO\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer)\n", - "seq = buffer.getvalue()\n", - "seq" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lecture" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'records': [{'nom': 'Xavier',\n", - " 'pr\u00e9nom': 'Xavier',\n", - " 'langages': [{'nom': 'C++', 'age': 40}, {'nom': 'Python', 'age': 20}]}]}" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from pickle import load\n", - "buffer = BytesIO(seq)\n", - "read = load(buffer)\n", - "read" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Les classes\n", - "\n", - "A l'inverse du format *JSON*, les classes sont s\u00e9rialisables avec *pickle* parce que le langage utilise un format tr\u00e8s proche de ce qu'il a en m\u00e9moire. Il n'a pas besoin de conversion suppl\u00e9mentaire." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x03c__main__\\nA\\nq\\x00)\\x81q\\x01}q\\x02X\\x03\\x00\\x00\\x00attq\\x03X\\x01\\x00\\x00\\x00rq\\x04sb.'" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data = A('r')\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer)\n", - "seq = buffer.getvalue()\n", - "seq" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "<__main__.A at 0x24ddb4c36d8>" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "buffer = BytesIO(seq)\n", - "read = load(buffer)\n", - "read" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### R\u00e9duire la taille\n", - "\n", - "Certaines informations sont duppliqu\u00e9es et il est pr\u00e9f\u00e9rable de ne pas les s\u00e9rialiser deux fois surtout si elles sont voluminueuses." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "class B:\n", - " def __init__(self, att):\n", - " self.att1 = att\n", - " self.att2 = att" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x03c__main__\\nB\\nq\\x00)\\x81q\\x01}q\\x02(X\\x04\\x00\\x00\\x00att1q\\x03X\\x01\\x00\\x00\\x00rq\\x04X\\x04\\x00\\x00\\x00att2q\\x05h\\x04ub.'" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data = B('r')\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer)\n", - "seq = buffer.getvalue()\n", - "seq" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Evitons maintenant de stocker deux fois le m\u00eame attribut." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x03c__main__\\nB\\nq\\x00)\\x81q\\x01}q\\x02X\\x03\\x00\\x00\\x00attq\\x03X\\x01\\x00\\x00\\x00rq\\x04sb.'" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class B:\n", - " def __init__(self, att):\n", - " self.att1 = att\n", - " self.att2 = att\n", - " \n", - " def __getstate__(self):\n", - " return dict(att=self.att1)\n", - " \n", - "data = B('r')\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer)\n", - "seq = buffer.getvalue()\n", - "seq" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "C'est plus court mais il faut inclure maintenant la relecture." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "<__main__.B at 0x24ddb4b9a90>" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class B:\n", - " def __init__(self, att):\n", - " self.att1 = att\n", - " self.att2 = att\n", - " \n", - " def __getstate__(self):\n", - " return dict(att=self.att1)\n", - " \n", - " def __setstate__(self, state):\n", - " setattr(self, 'att1', state[\"att\"])\n", - " setattr(self, 'att2', state[\"att\"])\n", - " \n", - "buffer = BytesIO(seq)\n", - "read = load(buffer)\n", - "read" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('r', 'r')" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "read.att1, read.att2" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4.05 \u00b5s \u00b1 349 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "data = B('r')\n", - "%timeit dump(data, BytesIO())" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5.8 \u00b5s \u00b1 874 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "%timeit load(BytesIO(seq))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La s\u00e9rialisation binaire est habituellement plus rapide dans les langages bas niveau comme C++. La m\u00eame comparaison pour un langage haut niveau tel que Python n'est pas toujours pr\u00e9visible. Il est possible d'acc\u00e9l\u00e9rer un peu les choses." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4.05 \u00b5s \u00b1 294 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "from pickle import HIGHEST_PROTOCOL\n", - "%timeit dump(data, BytesIO(), protocol=HIGHEST_PROTOCOL)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cas des fonctions\n", - "\n", - "La s\u00e9rialisation s'applique \u00e0 des donn\u00e9es et non \u00e0 du code mais le fait de s\u00e9rialiser des fonctions est tout de m\u00eame tentant. La s\u00e9rialisation binaire fonctionne m\u00eame avec les fonctions." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Binaire" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x03}q\\x00(X\\x01\\x00\\x00\\x00xq\\x01K\\x05X\\x01\\x00\\x00\\x00fq\\x02c__main__\\nmyfunc\\nq\\x03u.'" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def myfunc(x):\n", - " return x + 1\n", - "\n", - "data = {'x': 5, 'f': myfunc}\n", - "\n", - "from pickle import dump\n", - "from io import BytesIO\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer)\n", - "buffer.getvalue()" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'x': 5, 'f': }" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from pickle import load\n", - "res = load(BytesIO(buffer.getvalue()))\n", - "res" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "res['f'](res['x'])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La s\u00e9rialisation ne conserve pas le code de la fonction, juste son nom. Cela veut dire que si elle n'est pas disponible lorsqu'elle est appel\u00e9, il sera impossible de s'en servir." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Can't get attribute 'myfunc' on \n" - ] - } - ], - "source": [ - "del myfunc\n", - "\n", - "from pickle import load\n", - "try:\n", - " load(BytesIO(buffer.getvalue()))\n", - "except Exception as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Il est possible de contourner l'obstacle en utilisant le module [cloudpicke](https://github.com/cloudpipe/cloudpickle) qui stocke le code de la fonction." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x04\\x95\\x9b\\x01\\x00\\x00\\x00\\x00\\x00\\x00}\\x94(\\x8c\\x01x\\x94K\\x05\\x8c\\x01f\\x94\\x8c\\x17cloudpickle.cloudpickle\\x94\\x8c\\x0e_fill_function\\x94\\x93\\x94(h\\x03\\x8c\\x0f_make_skel_func\\x94\\x93\\x94h\\x03\\x8c\\r_builtin_type\\x94\\x93\\x94\\x8c\\x08CodeType\\x94\\x85\\x94R\\x94(K\\x01K\\x00K\\x01K\\x02KCC\\x08|\\x00d\\x01\\x17\\x00S\\x00\\x94NK\\x01\\x86\\x94)h\\x01\\x85\\x94\\x8c\\x1f\\x94\\x8c\\x06myfunc\\x94K\\x01C\\x02\\x00\\x01\\x94))t\\x94R\\x94J\\xff\\xff\\xff\\xff}\\x94(\\x8c\\x0b__package__\\x94N\\x8c\\x08__name__\\x94\\x8c\\x08__main__\\x94u\\x87\\x94R\\x94}\\x94(\\x8c\\x07globals\\x94}\\x94\\x8c\\x08defaults\\x94N\\x8c\\x04dict\\x94}\\x94\\x8c\\x0eclosure_values\\x94N\\x8c\\x06module\\x94h\\x18\\x8c\\x04name\\x94h\\x11\\x8c\\x03doc\\x94N\\x8c\\x17_cloudpickle_submodules\\x94]\\x94\\x8c\\x0bannotations\\x94}\\x94\\x8c\\x08qualname\\x94h\\x11\\x8c\\nkwdefaults\\x94NutRu.'" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def myfunc(x):\n", - " return x + 1\n", - "\n", - "data = {'x': 5, 'f': myfunc}\n", - "\n", - "from cloudpickle import dump\n", - "from io import BytesIO\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer)\n", - "buffer.getvalue()" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'x': 5, 'f': }" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "del myfunc\n", - "\n", - "from cloudpickle import load\n", - "res = load(BytesIO(buffer.getvalue()))\n", - "res" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "res['f'](res['x'])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### JSON" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La s\u00e9rialisation au format JSON ne fonctionne pas avec le module standard." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Object of type function is not JSON serializable\n" - ] - } - ], - "source": [ - "from json import dump\n", - "from io import StringIO\n", - "buffer = StringIO()\n", - "try:\n", - " dump(data, buffer) # 2\n", - "except Exception as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La s\u00e9rialisation avec *ujson* ne fonctionne pas non plus m\u00eame si elle ne produit pas toujours d'erreur." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'{\"x\":5,\"f\":{}}'" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from ujson import dump\n", - "from io import StringIO\n", - "buffer = StringIO()\n", - "try:\n", - " res = dump(data, buffer) # 3\n", - "except TypeError as e:\n", - " print(e)\n", - "buffer.getvalue()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cas des it\u00e9rateurs\n", - "\n", - "Les it\u00e9rateurs fonctionnent avec la s\u00e9rialisation binaire mais ceci implique de stocker l'ensemble que l'it\u00e9rateur parcourt." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x80\\x03}q\\x00(X\\x01\\x00\\x00\\x00xq\\x01K\\x05X\\x02\\x00\\x00\\x00itq\\x02cbuiltins\\niter\\nq\\x03]q\\x04(K\\x01K\\x02e\\x85q\\x05Rq\\x06K\\x00bu.'" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ens = [1, 2]\n", - "\n", - "data = {'x': 5, 'it': iter(ens)}\n", - "\n", - "from pickle import dump\n", - "from io import BytesIO\n", - "buffer = BytesIO()\n", - "res = dump(data, buffer) # 4\n", - "buffer.getvalue()" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'x': 5, 'it': }" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "del ens\n", - "from pickle import load\n", - "res = load(BytesIO(buffer.getvalue()))\n", - "res" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 2]" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(res[\"it\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(res[\"it\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cas des g\u00e9n\u00e9rateurs\n", - "\n", - "Ils ne peuvent \u00eatre s\u00e9rialis\u00e9s car le langage n'a pas acc\u00e8s \u00e0 l'ensemble des \u00e9l\u00e9ments que le g\u00e9n\u00e9rateur parcourt. Il n'y a aucun moyen de s\u00e9rialiser un g\u00e9n\u00e9rateur mais on peut s\u00e9rialiser la fonction qui cr\u00e9e le g\u00e9n\u00e9rateur." - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "can't pickle generator objects\n" - ] - } - ], - "source": [ - "def ensgen():\n", - " yield 1\n", - " yield 2\n", - "\n", - "data = {'x': 5, 'it': ensgen()}\n", - "\n", - "from pickle import dump\n", - "from io import BytesIO\n", - "buffer = BytesIO()\n", - "try:\n", - " dump(data, buffer)\n", - "except Exception as e:\n", - " print(e)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/_doc/notebooks/python/serialisation_protobuf.ipynb b/_doc/notebooks/python/serialisation_protobuf.ipynb deleted file mode 100644 index 51dc3811..00000000 --- a/_doc/notebooks/python/serialisation_protobuf.ipynb +++ /dev/null @@ -1,870 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# S\u00e9rialisation avec protobuf\n", - "\n", - "[protobuf](https://fr.wikipedia.org/wiki/Protocol_Buffers) optimise la s\u00e9rialisation de deux fa\u00e7ons. Elle acc\u00e9l\u00e8re l'\u00e9criture et la lecture des donn\u00e9es et permet aussi un acc\u00e8s rapide \u00e0 une information pr\u00e9cise dans d\u00e9s\u00e9rialiser les autres. Elle r\u00e9alise cela en imposant un sch\u00e9ma strict de donn\u00e9es." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sch\u00e9ma\n", - "\n", - "On r\u00e9cup\u00e8re l'exemple du [tutorial](https://developers.google.com/protocol-buffers/docs/pythontutorial)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "schema = \"\"\"\n", - "syntax = \"proto2\";\n", - "\n", - "package tutorial;\n", - "\n", - "message Person {\n", - " required string name = 1;\n", - " required int32 id = 2;\n", - " optional string email = 3;\n", - "\n", - " enum PhoneType {\n", - " MOBILE = 0;\n", - " HOME = 1;\n", - " WORK = 2;\n", - " }\n", - "\n", - " message PhoneNumber {\n", - " required string number = 1;\n", - " optional PhoneType type = 2 [default = HOME];\n", - " }\n", - "\n", - " repeated PhoneNumber phones = 4;\n", - "}\n", - "\n", - "message AddressBook {\n", - " repeated Person people = 1;\n", - "}\n", - "\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Compilation\n", - "\n", - "Il faut d'abord r\u00e9cup\u00e9rer le compilateur. Cela peut se faire depuis le site de [protobuf](https://github.com/google/protobuf/releases) ou sur Linux (Ubuntu/Debian) ``apt-get install protobuf-compiler`` pour obtenir le programme ``protoc``." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'3.5.1'" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import google.protobuf as gp\n", - "version = gp.__version__\n", - "if version == \"3.5.2.post1\":\n", - " version = \"3.5.1\"\n", - "version" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "protoc-3.5.1-win32.zip\n" - ] - } - ], - "source": [ - "import sys, os\n", - "\n", - "if sys.platform.startswith(\"win\"):\n", - " url = \"https://github.com/google/protobuf/releases/download/v{0}/protoc-{0}-win32.zip\".format(version)\n", - " name = \"protoc-{0}-win32.zip\".format(version)\n", - " exe = 'protoc.exe'\n", - "else:\n", - " url = \"https://github.com/google/protobuf/releases/download/v{0}/protoc-{0}-linux-x86_64.zip\".format(version)\n", - " exe = 'protoc'\n", - " name = \"protoc-{0}-linux-x86_64.zip\".format(version)\n", - "\n", - "protoc = os.path.join(\"bin\", exe)\n", - "if not os.path.exists(name):\n", - " from pyquickhelper.filehelper import download\n", - " try:\n", - " download(url)\n", - " except Exception as e:\n", - " raise Exception(\"Unable to download '{0}'\\nERROR\\n{1}\".format(url, e))\n", - "else:\n", - " print(name)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "if not os.path.exists(protoc):\n", - " from pyquickhelper.filehelper import unzip_files\n", - " unzip_files(name,where_to='.')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "if not os.path.exists(protoc):\n", - " raise FileNotFoundError(protoc)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On \u00e9crit le format sur disque." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "with open('schema.proto', 'w') as f:\n", - " f.write(schema)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Et on peut compiler." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "----\n", - "\n" - ] - } - ], - "source": [ - "from pyquickhelper.loghelper import run_cmd\n", - "cmd = '{0} --python_out=. schema.proto'.format(protoc)\n", - "try:\n", - " out, err = run_cmd(cmd=cmd, wait=True)\n", - "except PermissionError as e:\n", - " # Sous Linux si ne marche pas avec bin/protoc, on utilise\n", - " # protoc directement \u00e0 supposer que le package\n", - " # protobuf-compiler a \u00e9t\u00e9 install\u00e9.\n", - " if not sys.platform.startswith(\"win\"):\n", - " protoc = \"protoc\"\n", - " cmd = '{0} --python_out=. schema.proto'.format(protoc)\n", - " try:\n", - " out, err = run_cmd(cmd=cmd, wait=True)\n", - " except Exception as e:\n", - " mes = \"CMD: {0}\".format(cmd)\n", - " raise Exception(\"Unable to use {0}\\n{1}\".format(protoc, mes)) from e\n", - " else:\n", - " mes = \"CMD: {0}\".format(cmd)\n", - " raise Exception(\"Unable to use {0}\\n{1}\".format(protoc, mes)) from e\n", - "print(\"\\n----\\n\".join([out, err]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Un fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['schema_pb2.py']" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[_ for _ in os.listdir(\".\") if '.py' in _]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "# Generated by the protocol buffer compiler. DO NOT EDIT!\n", - "# source: schema.proto\n", - "\n", - "import sys\n", - "_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))\n", - "from google.protobuf import descriptor as _descriptor\n", - "from google.protobuf import message as _message\n", - "from google.protobuf import reflection as _reflection\n", - "from google.protobuf import symbol_database as _symbol_database\n", - "from google.protobuf import descriptor_pb2\n", - "# @@protoc_insertion_point(imports)\n", - "\n", - "_sym_db = _symbol_database.Default()\n", - "\n", - "\n", - "\n", - "\n", - "DESCRIPTOR = _descriptor.FileDescriptor(\n", - " name='schema.proto',\n", - " package='tutorial',\n", - " syntax='proto2',\n", - " serialized_pb=_b('\\n\\x0cschema.proto\\x12\\x08tutorial\\\"\\xdb\\x01\\n\\x06Person\\x12\\x0c\\n\\x04name\\x18\\x01 \\x02(\\t\\x12\\n\\n\\x02id\\x18\\x02 \\x02(\\x05\\x12\\r\\n\\x05\\x65mail\\x18\\x03 \\x01(\\t\\x12,\\n\\x06phones\\x18\\x04 \\x03(\\x0b\\x32\\x1c.tutorial.Person.PhoneNumber\\x1aM\\n\\x0bPhoneNumber\\x12\\x0e\\n\\x06number\\x18\\x01 \\x02(\\t\\x12.\\n\\x04type\\x18\\x02 \\x01(\\x0e\\x32\\x1a.tutorial.Person.PhoneType:\\x04HOME\\\"\n" - ] - } - ], - "source": [ - "with open('schema_pb2.py', 'r') as f:\n", - " content = f.read()\n", - "print(content[:1000])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import du module cr\u00e9\u00e9 \n", - "\n", - "Pour utliser *protobuf*, il faut importer le module cr\u00e9\u00e9." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import schema_pb2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On cr\u00e9\u00e9 un enregistrement." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "person = schema_pb2.Person()\n", - "person.id = 1234\n", - "person.name = \"John Doe\"\n", - "person.email = \"jdoe@example.com\"\n", - "phone = person.phones.add()\n", - "phone.number = \"555-4321\"\n", - "phone.type = schema_pb2.Person.HOME" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "name: \"John Doe\"\n", - "id: 1234\n", - "email: \"jdoe@example.com\"\n", - "phones {\n", - " number: \"555-4321\"\n", - " type: HOME\n", - "}" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "person" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## S\u00e9rialisation en cha\u00eene de caract\u00e8res" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(bytes,\n", - " b'\\n\\x08John Doe\\x10\\xd2\\t\\x1a\\x10jdoe@example.com\"\\x0c\\n\\x08555-4321\\x10\\x01')" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "res = person.SerializeToString()\n", - "type(res), res" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4.56 \u00b5s \u00b1 447 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "%timeit person.SerializeToString()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "name: \"John Doe\"\n", - "id: 1234\n", - "email: \"jdoe@example.com\"\n", - "phones {\n", - " number: \"555-4321\"\n", - " type: HOME\n", - "}" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pers = schema_pb2.Person.FromString(res)\n", - "pers" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "name: \"John Doe\"\n", - "id: 1234\n", - "email: \"jdoe@example.com\"\n", - "phones {\n", - " number: \"555-4321\"\n", - " type: HOME\n", - "}" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pers = schema_pb2.Person()\n", - "pers.ParseFromString(res)\n", - "pers" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.44 \u00b5s \u00b1 696 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "%timeit schema_pb2.Person.FromString(res)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.13 \u00b5s \u00b1 633 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n" - ] - } - ], - "source": [ - "%timeit pers.ParseFromString(res)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Plusieurs cha\u00eenes de caract\u00e8res" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "db = []\n", - "\n", - "person = schema_pb2.Person()\n", - "person.id = 1234\n", - "person.name = \"John Doe\"\n", - "person.email = \"jdoe@example.com\"\n", - "phone = person.phones.add()\n", - "phone.number = \"555-4321\"\n", - "phone.type = schema_pb2.Person.HOME\n", - "db.append(person)\n", - "\n", - "person = schema_pb2.Person()\n", - "person.id = 5678\n", - "person.name = \"Johnette Doette\"\n", - "person.email = \"jtdoet@example2.com\"\n", - "phone = person.phones.add()\n", - "phone.number = \"777-1234\"\n", - "phone.type = schema_pb2.Person.MOBILE\n", - "db.append(person)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'-\\x00\\x00\\x00\\n\\x08John Doe\\x10\\xd2\\t\\x1a\\x10jdoe@example.com\"\\x0c\\n\\x08555-4321\\x10\\x017\\x00\\x00\\x00\\n\\x0fJohnette Doette\\x10\\xae,\\x1a\\x13jtdoet@example2.com\"\\x0c\\n\\x08777-1234\\x10\\x00'" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import struct\n", - "from io import BytesIO\n", - "buffer = BytesIO()\n", - "for p in db:\n", - " size = p.ByteSize()\n", - " buffer.write(struct.pack('i', size))\n", - " buffer.write(p.SerializeToString())\n", - "res = buffer.getvalue()\n", - "res" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "from google.protobuf.internal.decoder import _DecodeVarint32\n", - "db2 = []\n", - "buffer = BytesIO(res)\n", - "n = 0\n", - "while True:\n", - " bsize = buffer.read(4)\n", - " if len(bsize) == 0:\n", - " # C'est fini.\n", - " break\n", - " size = struct.unpack('i', bsize)[0]\n", - " data = buffer.read(size)\n", - " p = schema_pb2.Person.FromString(data)\n", - " db2.append(p) " - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(name: \"John Doe\"\n", - " id: 1234\n", - " email: \"jdoe@example.com\"\n", - " phones {\n", - " number: \"555-4321\"\n", - " type: HOME\n", - " }, name: \"Johnette Doette\"\n", - " id: 5678\n", - " email: \"jtdoet@example2.com\"\n", - " phones {\n", - " number: \"777-1234\"\n", - " type: MOBILE\n", - " })" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "db2[0], db2[1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## S\u00e9rialisation JSON" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "from google.protobuf.json_format import MessageToJson" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"name\": \"John Doe\",\n", - " \"id\": 1234,\n", - " \"email\": \"jdoe@example.com\",\n", - " \"phones\": [\n", - " {\n", - " \"number\": \"555-4321\",\n", - " \"type\": \"HOME\"\n", - " }\n", - " ]\n", - "}\n" - ] - } - ], - "source": [ - "print(MessageToJson(pers))" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "76.4 \u00b5s \u00b1 7.48 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 10000 loops each)\n" - ] - } - ], - "source": [ - "%timeit MessageToJson(pers)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "name: \"John Doe\"\n", - "id: 1234\n", - "email: \"jdoe@example.com\"\n", - "phones {\n", - " number: \"555-4321\"\n", - " type: HOME\n", - "}" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from google.protobuf.json_format import Parse as ParseJson\n", - "js = MessageToJson(pers)\n", - "res = ParseJson(js, message=schema_pb2.Person())\n", - "res" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "75 \u00b5s \u00b1 7.77 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 10000 loops each)\n" - ] - } - ], - "source": [ - "%timeit ParseJson(js, message=schema_pb2.Person())" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/_doc/notebooks/python/tarabiscote.ipynb b/_doc/notebooks/python/tarabiscote.ipynb deleted file mode 100644 index 3dd9a8ca..00000000 --- a/_doc/notebooks/python/tarabiscote.ipynb +++ /dev/null @@ -1,838 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Exercices expliqu\u00e9s de programmation\n", - "\n", - "Quelques exercices autour de la copie de liste, du temps de calcul, de l'h\u00e9ritage." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
run previous cell, wait for 2 seconds
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from jyquickhelper import add_notebook_menu\n", - "add_notebook_menu()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Copie de listes\n", - "\n", - "La fonction ``somme`` est cens\u00e9e faire la concat\u00e9nation de toutes les listes contenues dans ``ens``. Le r\u00e9sultat retourn\u00e9 est effectivement celui d\u00e9sir\u00e9 mais la fonction modifie \u00e9galement la liste ``ens``, pourquoi ?" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 1, 2, 3]\n", - "[[0, 1, 2, 3], [2, 3]]\n" - ] - } - ], - "source": [ - "def somme(tab):\n", - " l = tab[0]\n", - " for i in range(1, len(tab)):\n", - " l += tab [i]\n", - " return l\n", - "\n", - "ens = [[0,1],[2,3]] \n", - "print(somme(ens))\n", - "print(ens)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le probl\u00e8me vient du fait qu'une affectation en *python* (seconde ligne de la fonction ``somme`` ne fait pas une copie mais cr\u00e9e un second identificateur pour d\u00e9signer la m\u00eame chose. Ici, ``l`` et ``tab[0]`` d\u00e9signent la m\u00eame liste, modifier l'une modifie l'autre. Ceci explique le r\u00e9sultat. Pour corriger, il fallait faire une copie explicite de ``tab[0]`` :" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 1, 2, 3]\n", - "[[0, 1], [2, 3]]\n" - ] - } - ], - "source": [ - "import copy ###### ligne ajout\u00e9e\n", - "def somme(tab):\n", - " l = copy.copy (tab[0]) ###### ligne modifi\u00e9e\n", - " for i in range(1, len (tab)):\n", - " l += tab[i]\n", - " return l\n", - "\n", - "ens = [[0,1],[2,3]] \n", - "print(somme(ens))\n", - "print(ens)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Il \u00e9tait possible, dans ce cas, de se passer de copie en \u00e9crivant :" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 1, 2, 3]\n", - "[[0, 1], [2, 3]]\n" - ] - } - ], - "source": [ - "def somme(tab) :\n", - " l = [] ###### ligne modifi\u00e9e\n", - " for i in range (0, len (tab)) : ###### ligne modifi\u00e9e\n", - " l += tab [i]\n", - " return l\n", - "\n", - "ens = [[0,1],[2,3]] \n", - "print(somme(ens))\n", - "print(ens)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Erreur de logique\n", - "\n", - "Le programme suivant fonctionne mais le r\u00e9sultat n'est pas celui escompt\u00e9. " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['un', 'deux', 'deux', 'deux', 'cinq']" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l = [\"un\", \"deux\", \"trois\", \"quatre\", \"cinq\"]\n", - "\n", - "for i in range (0,len (l)) :\n", - " mi = i\n", - " for j in range (i, len (l)) :\n", - " if l[mi] < l [j] : mi = j\n", - " e = l [i]\n", - " l [mi] = l [i]\n", - " l [i] = e\n", - "\n", - "l" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ce programme est cens\u00e9 effectuer un tri par ordre alphab\u00e9tique **d\u00e9croissant**. Le probl\u00e8me intervient lors de la permutation de l'\u00e9l\u00e9ment ``l[i]`` avec l'\u00e9l\u00e9ment ``l[mi]``. Il faut donc \u00e9crire :" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['un', 'trois', 'quatre', 'deux', 'cinq']" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l = [\"un\", \"deux\", \"trois\", \"quatre\", \"cinq\"]\n", - "for i in range (0,len (l)) :\n", - " mi = i\n", - " for j in range (i, len (l)) :\n", - " if l[mi] < l [j] : mi = j\n", - " e = l [mi] ######## ligne modifi\u00e9e\n", - " l [mi] = l [i]\n", - " l [i] = e\n", - " \n", - "l" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Co\u00fbt d'un algorithme\n", - "\n", - "Le co\u00fbt d'un algorithme ou d'un programme est le nombre d'op\u00e9rations (additions, multiplications, tests, ...) qu'il effectue. Il s'exprime comme un multiple d'une fonction de la dimension des donn\u00e9es que le programme manipule. Par exemple : $O(n)$, $O(n^2)$, $O(n\\ln n)$, ..." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.5\n", - "1.25\n" - ] - } - ], - "source": [ - "def moyenne (tab) :\n", - " s = 0.0\n", - " for x in tab : \n", - " s += x\n", - " return s / len (tab)\n", - " \n", - "def variance (tab) :\n", - " s = 0.0\n", - " for x in tab :\n", - " t = x - moyenne (tab)\n", - " s += t * t\n", - " return s / len (tab)\n", - " \n", - "l = [ 0,1,2, 2,3,1,3,0]\n", - "print(moyenne (l))\n", - "print(variance (l))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Tout d'abord, le co\u00fbt d'un algorithme est tr\u00e8s souvent exprim\u00e9 comme un multiple de la dimension des donn\u00e9es qu'il traite. Ici, la dimension est la taille du tableau ``tab``. Par exemple, si on note ``n = len(tab)``, alors le co\u00fbt de la fonction ``moyenne`` s'\u00e9crit $O(n)$ car cette fonction fait la somme des $n$ \u00e9l\u00e9ments du tableau.\n", - "\n", - "La fonction ``variance`` contient quant \u00e0 elle un petit pi\u00e8ge. Si elle contient elle aussi une boucle, chacun des $n$ passages dans cette boucle fait appel \u00e0 la fonction ``moyenne``. Le co\u00fbt de la fonction ``variance`` est donc \n", - "$O(n^2)$.\n", - "\n", - "Il est possible d'acc\u00e9l\u00e9rer le programme car la fonction ``moyenne`` retourne le m\u00eame r\u00e9sultat \u00e0 chaque passage dans la boucle. Il suffit de m\u00e9moriser son r\u00e9sultat dans une variable avant d'entrer dans la boucle comme suit :" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1.25" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def variance (tab) :\n", - " s = 0.0\n", - " m = moyenne (tab)\n", - " for x in tab :\n", - " t = x - m\n", - " s += t * t\n", - " return s / len (tab)\n", - "\n", - "variance(l)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le co\u00fbt de la fonction ``variance`` est alors $O(n)$." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le co\u00fbt d'un algorithme peut \u00eatre \u00e9valu\u00e9 de mani\u00e8re plus pr\u00e9cise et n\u00e9cessiter un r\u00e9sultat comme $n^2 + 3n + 2$ mais cette exigence est rarement utile pour des langages comme *python*. L'expression ``for x in tab:`` cache n\u00e9cessairement un test qu'il faudrait prendre en compte si plus de pr\u00e9cision \u00e9tait exig\u00e9e. Il faudrait \u00e9galement se tourner vers un autre langage de programmation, plus pr\u00e9cis dans sa syntaxe. Par exemple, lorsqu'on con\u00e7oit un programme avec le langage C ou C++, \u00e0 partir du m\u00eame code informatique, on peut construire deux programmes ex\u00e9cutables. Le premier (ou version *debug*), lent, sert \u00e0 la mise au point : il inclut des tests suppl\u00e9mentaires permettant de v\u00e9rifier \u00e0 chaque \u00e9tape qu'il n'y a pas eu d'erreur (une division par z\u00e9ro par exemple). Lorsqu'on est s\u00fbr que le programme marche, on construit la seconde version (ou *release*), plus rapide, dont ont \u00e9t\u00e9 \u00f4t\u00e9s tous ces tests de conception devenus inutiles. \n", - "\n", - "*python* aboutit \u00e0 un programme lent qui inclut une quantit\u00e9 de tests invisibles pour celui qui programme mais qui d\u00e9tecte les erreurs plus vite et favorise une conception rapide. Il n'est pas adapt\u00e9 au traitement d'information en grand nombre et fait une multitude d'op\u00e9rations cach\u00e9es." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## H\u00e9ritage double\n", - "\n", - "On a besoin dans un programme de cr\u00e9er une classe ``carre`` et une classe ``rectangle``. Mais on ne sait pas quelle classe doit h\u00e9riter de l'autre. Dans le premier programme, ``rectangle`` h\u00e9rite de ``carre``." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class carre:\n", - " def __init__ (self, a):\n", - " self.a = a\n", - " def surface (self):\n", - " return self.a ** 2\n", - "\n", - "class rectangle(carre):\n", - " def __init__ (self, a,b) :\n", - " carre.__init__(self,a)\n", - " self.b = b\n", - " def surface (self):\n", - " return self.a * self.b\n", - "\n", - "rectangle(3, 4).surface()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Dans le second programme, c'est la classe ``carre`` qui h\u00e9rite de la classe ``rectangle``." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "9" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class rectangle :\n", - " def __init__ (self, a,b) :\n", - " self.a = a\n", - " self.b = b\n", - " def surface (self) :\n", - " return self.a * self.b\n", - "\n", - "class carre (rectangle) :\n", - " def __init__ (self, a) :\n", - " rectangle.__init__ (self, a,a)\n", - " def surface (self) :\n", - " return self.a ** 2\n", - " \n", - "carre(3).surface()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* Dans le second programme, est-il n\u00e9cessaire de red\u00e9finir la m\u00e9thode ``surface`` dans la classe ``carre`` ?\n", - "* Quel est le sens d'h\u00e9ritage qui vous para\u00eet le plus cens\u00e9, ``class rectangle(carre)`` ou ``class carre(rectangle)`` ?\n", - "* On d\u00e9sire ajouter la classe ``losange``. Est-il plus simple que ``rectangle`` h\u00e9rite de la classe ``carre`` ou l'inverse pour introduire la classe ``losange`` ? Quel ou quels attributs suppl\u00e9mentaires faut-il introduire dans la classe ``losange`` ?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le principe de l'h\u00e9ritage est qu'une classe ``carre`` h\u00e9ritant de la classe ``rectangle`` h\u00e9rite de ses attributs et m\u00e9thodes. L'aire d'un carr\u00e9 est \u00e9gale \u00e0 celle d'un rectangle dont les c\u00f4t\u00e9s sont \u00e9gaux, par cons\u00e9quent, la m\u00e9thode ``surface`` de la classe retourne la m\u00eame valeur que celle de la classe ``rectangle``. Il n'est donc pas n\u00e9cessaire de la red\u00e9finir.\n", - "* D'apr\u00e8s la r\u00e9ponse de la premi\u00e8re question, il para\u00eet plus logique de consid\u00e9rer que ``carre`` h\u00e9rite de ``rectangle``.\n", - "* Un losange est d\u00e9fini par un c\u00f4t\u00e9 et un angle ou un c\u00f4t\u00e9 et la longueur d'une de ses diagonales, soit dans les deux cas, deux param\u00e8tres. Dans la premi\u00e8re question, il paraissait plus logique que la classe la plus sp\u00e9cifique h\u00e9rite de la classe la plus g\u00e9n\u00e9rale afin de b\u00e9n\u00e9ficier de ses m\u00e9thodes. Pour introduire le losange, il para\u00eet plus logique de partir du plus sp\u00e9cifique pour aller au plus g\u00e9n\u00e9ral afin que chaque classe ne contienne que les informations qui lui sont n\u00e9cessaires." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "8.183676841431136" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import math\n", - "\n", - "class carre :\n", - " def __init__ (self, a) :\n", - " self.a = a\n", - " def surface (self) :\n", - " return self.a ** 2\n", - "\n", - "class rectangle (carre) :\n", - " def __init__ (self, a,b) :\n", - " carre.__init__(self,a)\n", - " self.b = b\n", - " def surface (self) :\n", - " return self.a * self.b\n", - "\n", - "class losange (carre) :\n", - " def __init__ (self, a,theta) :\n", - " carre.__init__(self,a)\n", - " self.theta = theta\n", - " def surface (self) :\n", - " return self.a * math.cos (self.theta) * self.a * math.sin (self.theta) * 2\n", - " \n", - "losange(3, 1).surface()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le sens de l'h\u00e9ritage d\u00e9pend de vos besoins. Si l'h\u00e9ritage porte principalement sur les m\u00e9thodes, il est pr\u00e9f\u00e9rable de partir du plus g\u00e9n\u00e9ral pour aller au plus sp\u00e9cifique. La premi\u00e8re classe sert d'interface pour toutes ses filles. Si l'h\u00e9ritage porte principalement sur les attributs, il est pr\u00e9f\u00e9rable de partir du plus sp\u00e9cifique au plus g\u00e9n\u00e9ral. Dans le cas g\u00e9n\u00e9ral, il n'y a pas d'h\u00e9ritage plus sens\u00e9 qu'un autre mais pour un probl\u00e8me donn\u00e9, il y a souvent un h\u00e9ritage plus sens\u00e9 qu'un autre. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pr\u00e9cision des calculs\n", - "\n", - "Voici un aper\u00e7u de la pr\u00e9cision des calculs pour le calcul $1 - 10^{-n}$. L'exercice a pour but de montrer que l'ordinateur ne fait que des calculs approch\u00e9s et que la pr\u00e9cision du r\u00e9sultat d\u00e9pend de la m\u00e9thode num\u00e9rique employ\u00e9e." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 \t 0.9 \t 0.1 \t 0.31622776601683794\n", - "1 \t 0.99 \t 0.01 \t 0.1\n", - "2 \t 0.999 \t 0.001 \t 0.03162277660168379\n", - "3 \t 0.9999 \t 0.0001 \t 0.01\n", - "4 \t 0.99999 \t 1e-05 \t 0.0031622776601683794\n", - "5 \t 0.999999 \t 1.0000000000000002e-06 \t 0.001\n", - "6 \t 0.9999999 \t 1.0000000000000002e-07 \t 0.000316227766016838\n", - "7 \t 0.99999999 \t 1.0000000000000002e-08 \t 0.0001\n", - "8 \t 0.999999999 \t 1.0000000000000003e-09 \t 3.1622776601683795e-05\n", - "9 \t 0.9999999999 \t 1.0000000000000003e-10 \t 1e-05\n", - "10 \t 0.99999999999 \t 1.0000000000000003e-11 \t 3.1622776601683796e-06\n", - "11 \t 0.999999999999 \t 1.0000000000000002e-12 \t 1.0000000000000002e-06\n", - "12 \t 0.9999999999999 \t 1.0000000000000002e-13 \t 3.1622776601683797e-07\n", - "13 \t 0.99999999999999 \t 1.0000000000000002e-14 \t 1.0000000000000001e-07\n", - "14 \t 0.999999999999999 \t 1e-15 \t 3.162277660168379e-08\n", - "15 \t 0.9999999999999999 \t 1.0000000000000001e-16 \t 1e-08\n", - "16 \t 1.0 \t 1e-17 \t 3.1622776601683795e-09\n", - "17 \t 1.0 \t 1e-18 \t 1e-09\n", - "18 \t 1.0 \t 1.0000000000000001e-19 \t 3.1622776601683795e-10\n" - ] - } - ], - "source": [ - "x = 1.0\n", - "for i in range (0,19) :\n", - " x = x / 10\n", - " print(i, \"\\t\", 1.0 - x, \"\\t\", x, \"\\t\", x **(0.5))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Le programme montre que l'ordinateur affiche ``1`` lorsqu'il calcule $1-10^{-17}$. Cela signifie que la pr\u00e9cision des calculs en *python* est au mieux de $10^{-16}$. C'est encore moins bon dans le cas de *float* ou r\u00e9el simple pr\u00e9cision cod\u00e9 sur 4 octets au lieu de 8 pour les *double*." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 \t 0.8999999985098839 \t 0.1 \t 0.3162277683729184\n", - "1 \t 0.9900000002235174 \t 0.01 \t 0.0999999988824129\n", - "2 \t 0.9990000000689179 \t 0.0009999999 \t 0.03162277551199656\n", - "3 \t 0.9999000000098022 \t 9.999999e-05 \t 0.009999999509891484\n", - "4 \t 0.9999900000011621 \t 9.999999e-06 \t 0.0031622774764217087\n", - "5 \t 0.9999990000001162 \t 9.999999e-07 \t 0.0009999999418942008\n", - "6 \t 0.999999900000013 \t 9.999999e-08 \t 0.0003162277453952373\n", - "7 \t 0.999999990000001 \t 9.999999e-09 \t 9.999999525523424e-05\n", - "8 \t 0.9999999990000001 \t 9.999999e-10 \t 3.162277439909038e-05\n", - "9 \t 0.9999999999 \t 9.999999e-11 \t 9.99999937286775e-06\n", - "10 \t 0.99999999999 \t 9.999999e-12 \t 3.162277516708525e-06\n", - "11 \t 0.999999999999 \t 9.999999e-13 \t 9.999999437919884e-07\n", - "12 \t 0.9999999999999 \t 9.999999e-14 \t 3.162277525279896e-07\n", - "13 \t 0.99999999999999 \t 9.999999e-15 \t 9.999999488741863e-08\n", - "14 \t 0.999999999999999 \t 9.999999e-16 \t 3.162277498494361e-08\n", - "15 \t 0.9999999999999999 \t 9.999999e-17 \t 9.999999422567411e-09\n", - "16 \t 1.0 \t 9.999999e-18 \t 3.162277503725911e-09\n", - "17 \t 1.0 \t 9.999999e-19 \t 9.999999712080637e-10\n", - "18 \t 1.0 \t 1e-19 \t 3.1622776099917643e-10\n" - ] - } - ], - "source": [ - "import numpy\n", - "x = numpy.float32(1.0)\n", - "for i in range (0,19) :\n", - " x = x / numpy.float32(10)\n", - " print(i, \"\\t\", 1.0 - x, \"\\t\", x, \"\\t\", x **(0.5))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On \u00e9crit une classe ``matrice_carree_2`` qui repr\u00e9sente une matrice carr\u00e9e de dimension 2." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0.999999999999\n", - "1.0\n" - ] - } - ], - "source": [ - "class matrice_carree_2 :\n", - " def __init__ (self, a,b,c,d) :\n", - " self.a, self.b, self.c, self.d = a,b,c,d\n", - " \n", - " def determinant (self) :\n", - " return self.a * self.d - self.b * self.c\n", - " \n", - "m1 = matrice_carree_2 (1.0,1e-6,1e-6,1.0)\n", - "m2 = matrice_carree_2 (1.0,1e-9,1e-9,1.0)\n", - "print(m1.determinant())\n", - "print(m2.determinant())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La seconde valeur est donc fausse. On consid\u00e8re maintenant la matrice $M = \\left(\\begin{array}{cc} 1 & 10^{-9} \\\\ 10^{-9} & 1 \\end{array} \\right)$.\n", - "\n", - "On pose $D = \\det(M) = 1 - 10^{-18}$ et $T = tr(M) = 2$. $\\Delta$ est le d\u00e9terminant de $M$ et $T$ sa trace. On sait que les valeurs propres de $M$ not\u00e9es $\\lambda_1, \\lambda_2$ v\u00e9rifient :\n", - "\n", - "$$\n", - "\\begin{array}{lll}\n", - "D &=& \\lambda_1 \\lambda_2 \\\\\n", - "T &=& \\lambda_1 + \\lambda_2\n", - "\\end{array}\n", - "$$\n", - "\n", - "On v\u00e9rifie que $(x - \\lambda_1)(x - \\lambda_2) = x^2 - x (\\lambda_1 + \\lambda_2) + \\lambda_1 \\lambda_2$. Les valeurs propres de $M$ sont donc solutions de l'\u00e9quation : $x^2 - T x + D = 0$. \n", - "\n", - "Le discriminant de ce polyn\u00f4me est $\\Delta = T^2 - 4 D$. On peut donc exprimer les valeurs propres de la matrice $M$ par : \n", - "\n", - "$$\n", - "\\begin{array}{lll}\n", - "\\lambda_1 &=& \\frac{T - \\sqrt{\\Delta}}{2} \\\\\n", - "\\lambda_2 &=& \\frac{T + \\sqrt{\\Delta}}{2} \n", - "\\end{array}\n", - "$$\n", - "\n", - "On ajoute donc la m\u00e9thode suivante \u00e0 la classe ``matrice_carree_2`` :" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(0.9999990000110609, 1.000000999988939)\n", - "(1.0, 1.0)\n" - ] - } - ], - "source": [ - "class matrice_carree_2 :\n", - " def __init__ (self, a,b,c,d) :\n", - " self.a, self.b, self.c, self.d = a,b,c,d\n", - " \n", - " def determinant (self) :\n", - " return self.a * self.d - self.b * self.c\n", - " \n", - " def valeurs_propres (self) :\n", - " det = self.determinant ()\n", - " trace = self.a + self.d\n", - " delta = trace ** 2 - 4 * det\n", - " l1 = 0.5 * (trace - (delta ** (0.5)) )\n", - " l2 = 0.5 * (trace + (delta ** (0.5)) )\n", - " return l1,l2\n", - " \n", - "m1 = matrice_carree_2 (1.0,1e-6,1e-6,1.0)\n", - "m2 = matrice_carree_2 (1.0,1e-9,1e-9,1.0)\n", - "print(m1.valeurs_propres())\n", - "print(m2.valeurs_propres())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "D'apr\u00e8s l'\u00e9nonc\u00e9, les valeurs propres de la matrice $M_2$ sont les sommes de celles de la matrice $I$ et de la matrice $M'_2$. Par cons\u00e9quent, ce second calcul m\u00e8ne au r\u00e9sultat suivant :\n", - "\n", - "```\n", - "l1 = 1-1e-9 = 0.99999999900000002828\n", - "l2 = 1+ 1e-9 = 1.000000001\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La pr\u00e9cision des calculs prend sont importance ici. On d\u00e9compose la matrice $M = \\left(\\begin{array}{cc} 1 & 0 \\\\ 0 & 1 \\end{array}\\right) + \\left(\\begin{array}{cc} 0 & 10^{-9} \\\\ 10^{-9} & 0 \\end{array}\\right) = I + M'$. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On peut d\u00e9montrer que si $\\lambda$ est une valeur propre de $M'$, alors $1 + \\lambda$ est une valeur propre de $M$. Que donne le calcul des valeurs propres de $M'$ si on utilise la m\u00e9thode ``valeurs_propres`` pour ces deux matrices ?\n", - "\n", - "On consid\u00e8re maintenant la matrice $M'' = \\left(\\begin{array}{cc} 1 & 10^{-9} \\\\ -10^{-9} & 1 \\end{array}\\right)$. En d\u00e9composant la matrice $M''$ de la m\u00eame mani\u00e8re qu'\u00e0 la question 4, quelles sont les valeurs propres retourn\u00e9es par le programme pour la matrice $M''$ ? Quelles sont ses vraies valeurs propres ?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "La matrice $M''$ n'est en fait pas diagonalisable, c'est-\u00e0-dire que $tr(M'')^2 - 4 * \\det{M''} = 4 - 4 (1 + 10^{-18}) < 0$. Or le calcul propos\u00e9 par la question 3 aboutit au m\u00eame r\u00e9sultat faux que pour la matrice $M_2$, les deux valeurs propres trouv\u00e9es seront \u00e9gales \u00e0 1. Si on applique la d\u00e9composition propos\u00e9e :\n", - "$M'' = I + \\left(\\begin{array}{cc}0&-10^{-9}\\\\10^{-9}&0\\end{array}\\right) = I + N''$\n", - "Le programme calcule sans erreur le discriminant n\u00e9gatif de la matrice $N''$ qui n'est pas diagonalisable. Il est donc impossible d'obtenir des valeurs propres r\u00e9elles pour la matrice $M''$ avec cette seconde m\u00e9thode. Cette question montre qu'une erreur d'approximation peut rendre une matrice diagonalisable alors qu'elle ne l'est pas. Il faut bien choisir cette pr\u00e9cision en fonction de la destination des calculs." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/_doc/sphinxdoc/source/HISTORY.rst b/_doc/sphinxdoc/source/HISTORY.rst deleted file mode 100644 index f52fe6ab..00000000 --- a/_doc/sphinxdoc/source/HISTORY.rst +++ /dev/null @@ -1,22 +0,0 @@ - -.. _l-HISTORY: - -======= -History -======= - -current - 2021-01-01 - 0.00Mb -============================= - -0.0.0 - 2021-01-01 - 0.00Mb -=========================== - -* :issue:`14`: Aborder la notation f"" (2019-12-22) -* :issue:`10`: talk about warnings (2018-09-23) -* :issue:`6`: remove double entries in index (website) (2018-09-23) -* :issue:`9`: move pandas_groupby_nan to pandas_streaming (2018-05-17) -* :issue:`8`: talk about protobuf (2018-04-21) -* :issue:`7`: talk about serialization (2018-04-20) -* :issue:`5`: fix .. only:: html in readme.rst (2018-03-29) -* :issue:`2`: finish the migration of latex (2017-06-10) -* :issue:`1`: completed completion (2016-09-25) diff --git a/_doc/sphinxdoc/source/_static/my-styles.css b/_doc/sphinxdoc/source/_static/my-styles.css deleted file mode 100644 index a51da6d8..00000000 --- a/_doc/sphinxdoc/source/_static/my-styles.css +++ /dev/null @@ -1,30 +0,0 @@ -.admonition-mathdef { - color: #424242; - background-color: #F9F9F9; - font-size: 14px; -} -.admonition-todoext { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-faqref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-exref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-nbref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-blocref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} diff --git a/_doc/sphinxdoc/source/blog/2016/2016-08-18_first_blog.rst b/_doc/sphinxdoc/source/blog/2016/2016-08-18_first_blog.rst deleted file mode 100644 index 19614322..00000000 --- a/_doc/sphinxdoc/source/blog/2016/2016-08-18_first_blog.rst +++ /dev/null @@ -1,8 +0,0 @@ - -.. blogpost:: - :title: Premier blog, juste un essai - :keywords: - :date: 2016-09-18 - :categories: blog - - Premier blog. diff --git a/_doc/sphinxdoc/source/blog/2016/2016-11-20_groupby_nan.rst b/_doc/sphinxdoc/source/blog/2016/2016-11-20_groupby_nan.rst deleted file mode 100644 index fa9d88ed..00000000 --- a/_doc/sphinxdoc/source/blog/2016/2016-11-20_groupby_nan.rst +++ /dev/null @@ -1,11 +0,0 @@ - -.. blogpost:: - :title: pandas, groupby, nan values - :keywords: - :date: 2016-11-20 - :categories: pandas - - La fonction `groupby `_ - ne considère pas (plus) les valeurs manquantes ou - `NaN `_. - Le notebook :ref:`pandasgroupbyrst` illustre ce fait et montre comment les corriger. diff --git a/_doc/sphinxdoc/source/blog/2017/2017-01-06_programming.rst b/_doc/sphinxdoc/source/blog/2017/2017-01-06_programming.rst deleted file mode 100644 index a36d7051..00000000 --- a/_doc/sphinxdoc/source/blog/2017/2017-01-06_programming.rst +++ /dev/null @@ -1,29 +0,0 @@ - -.. blogpost:: - :title: I hate programming sometimes - :keywords: - :date: 2017-01-06 - :categories: weird - - This is the kind of example I never imagined - maybe because I trust too much the code I write - and I can't see it fail for something like what - follows. - - .. runpython:: - :showcode: - :nopep8: - - s1 = 'İ' - s2 = s1.lower() - print(s1, s2) - print(len(s1), len(s2)) - - b = bytes(s2, "utf-8") - print(chr(b[0]), chr(b[1])) - - Do you believe it? - - The length of a lower case character is longer. - - I need a drink. diff --git a/_doc/sphinxdoc/source/blog/2017/2017-07-01_cextension.rst b/_doc/sphinxdoc/source/blog/2017/2017-07-01_cextension.rst deleted file mode 100644 index b5359844..00000000 --- a/_doc/sphinxdoc/source/blog/2017/2017-07-01_cextension.rst +++ /dev/null @@ -1,29 +0,0 @@ - -.. blogpost:: - :title: Inclure un partie C dans un module Python - :keywords: python, C - :date: 2017-07-01 - :categories: module - - Je me suis amusé à programmer un module Python - qui inclut des fonctions écrites en C. - J'ai ajouté un build automatique sur - `travis `_ et - `appveyor `_. - La documentation du module - `cpyquickhelper `_ - et le code sur `github `_. - - Parmi les choses à retenir, il faut un compilateur C++, - `Visual Studio Community Edition 2015 `_ - et `gcc `_ - sous Linux. Pour construire l'extension : - - :: - - python setup.y build_ext --inplace - - Le paramètre ``--inplace`` précise que le module doit être compilé - sur place. Le module peut alors être importé. La partie intéressante - commence - `ici `_. diff --git a/_doc/sphinxdoc/source/blog/2018/2018-03-31_classesfonctions.rst b/_doc/sphinxdoc/source/blog/2018/2018-03-31_classesfonctions.rst deleted file mode 100644 index 29bdc2d4..00000000 --- a/_doc/sphinxdoc/source/blog/2018/2018-03-31_classesfonctions.rst +++ /dev/null @@ -1,174 +0,0 @@ - -.. blogpost:: - :title: C'est obligé les classes ? - :keywords: python, classes - :date: 2018-03-31 - :categories: classe - :label: blog-class-ou-fonction - - *Monsieur, c'est obligé d'utiliser les classes ?* - C'est une question qu'on me pose chaque année - lors des projets informatiques - et je réponds chaque année que non, les classes - ne sont pas obligatoires mais qu'elles ont le don - de simplifier l'écriture des programmes. - Le lanage :epkg:`Python` propose une des syntaxes - les plus explicites par rapport à d'autres langages - car il n'y a pas de paramètres cachés. - Le programme suivant calcule la somme et le produit - de deux entiers stockés dans un dictionnaire. - - .. runpython:: - :showcode: - - def deux_entiers_somme(de): - return de['i1'] + de['i2'] - - def deux_entiers_multiplication(de): - return de['i1'] * de['i2'] - - de = {'i1': 3, 'i2': 2} - s = deux_entiers_somme(de) - m = deux_entiers_multiplication(de) - print(s, m) - - Les deux fonctions ne sont applicables qu'à deux entiers. - Il paraît normal de les préfixer avec *deux_entiers* - pour signifier à celui qui les utiliser que ça ne sert - à rien de les utiliser pour autre chose. - Les classes permettent de regrouper formellement - ces deux fonctions. - - .. runpython:: - :showcode: - - class DeuxEntiers: - - def somme(de): - return de['i1'] + de['i2'] - - def multiplication(de): - return de['i1'] * de['i2'] - - de = {'i1': 3, 'i2': 2} - s = DeuxEntiers.somme(de) # _ --> . - m = DeuxEntiers.multiplication(de) # _ --> . - print(s, m) - - On a juste remplacé le signe ``_`` par ``.`` qui signifie - que la fonction cherchée est dans la classe qui précède ``.``. - Comme les deux entiers en questions sont toujours liés - aux fonctions qui les manipulent, il paraît normal de les - inclure dans la classe. - - .. runpython:: - :showcode: - - class DeuxEntiers: - - def __init__(self, de): # on accroche les données à la classe - self.de = de - - def somme(self): - return self.de['i1'] + self.de['i2'] - - def multiplication(self): - return self.de['i1'] * self.de['i2'] - - de = DeuxEntiers({'i1': 3, 'i2': 2}) - s = DeuxEntiers.somme(de) - m = DeuxEntiers.multiplication(de) - print(s, m) - - .. index:: méthode - - Comme le concept a beaucoup plu aux informaticiens, - ils ont cherché à simplifier l'appel aux fonctions qu'ils - ont appelé des *méthodes* : - - .. runpython:: - :showcode: - - class DeuxEntiers: - - def __init__(self, de): - self.de = de - - def somme(self): - return self.de['i1'] + self.de['i2'] - - def multiplication(self): - return self.de['i1'] * self.de['i2'] - - de = DeuxEntiers({'i1': 3, 'i2': 2}) - s = de.somme() # disparition de DeuxEntiers - m = de.multiplication() # disparition de DeuxEntiers - print(s, m) - - .. index:: attribut - - Ensuite, ils se sont penchés sur la simplification de la représentation - des deux entiers ``{'i1': 3, 'i2': 2}``. Et s'ils étaient considérés comme - des variables de la classe qui ont été renommés en *attributs*. - - .. runpython:: - :showcode: - - class DeuxEntiers: - - def __init__(self, i1, i2): - self.i1 = i1 # plus de dictionnaire - self.i2 = i2 - - def somme(self): - return self.i1 + self.i2 # plus de dictionnaire - - def multiplication(self): - return self.i1 * self.i2 # plus de dictionnaire - - de = DeuxEntiers(3, 2) # plus de dictionnaire - s = de.somme() - m = de.multiplication() - print(s, m) - - Les classes permettent de regrouper formellement - les fonctions qui ne s'appliquent toujours aux mêmes - données. Plus encore, ce nouveau concept a permis d'en - introduire un autre, l':ref:`par_classe_heritage`, qui - permet de réutiliser certaines fonctions, d'en remplacer - d'autres et d'en ajouter pour une autre situation. - - .. runpython:: - :showcode: - - class DeuxEntiers: - - def __init__(self, i1, i2): - self.i1 = i1 - self.i2 = i2 - - def somme(self): - return self.i1 + self.i2 - - def multiplication(self): - return self.i1 * self.i2 - - class DeuxEntiersModifies(DeuxEntiers): # héritage - - def multiplication(self): - return abs(self.i1 * self.i2) # modifié - - def division(self): - return abs(self.i1 / self.i2) # ajouté - - de = DeuxEntiersModifies(-3, 2) - s = de.somme() - m = de.multiplication() - d = de.division() - print(s, m, d) - - Cela peut paraît anodin mais la grande majorité des - programmeurs utilisent majoritairement les classes - une fois qu'ils les ont découvertes car elles - permettent d'organiser le code informatique - en bloc logique. diff --git a/_doc/sphinxdoc/source/blog/2018/2018-04-05_debug.rst b/_doc/sphinxdoc/source/blog/2018/2018-04-05_debug.rst deleted file mode 100644 index b8cf8dd7..00000000 --- a/_doc/sphinxdoc/source/blog/2018/2018-04-05_debug.rst +++ /dev/null @@ -1,34 +0,0 @@ - -.. blogpost:: - :title: Debugger Python - :keywords: python, classes - :date: 2018-04-05 - :categories: debug - - L'exécution pas à pas d'un programme - :epkg:`Python` permet souvent de trouver - facilement l'erreur caché dans un programme. - Cette astuce est néanmoins compliquée à mettre - en oeuvre dans deux cas. Le premier lorsque l'erreur - se produit dans un module implémentée en :epkg:`C++`. - C'est assez rare pour les modules standard comme - :epkg:`pandas` ou :epkg:`numpy` mais néanmoins possible. - Il n'y a pas d'options pratique depuis :epkg:`Python` - si ce n'est Visual Studio : - `Débogage conjoint de Python et de C++ - `_. - Le second cas difficile avec un débugger survient - lorsque l'erreur se produit dans un programme après plusieurs - minutes d'exécution ou à la dernière itération d'une boucle - à un million de tours. Dans ces cas-là, le seul recours - est souvent d'utiliser la fonction ``print`` à des endroits - bien choisis. Parfois, on souhaite détecter que le même nombre - d'objets à été créés puis détruits, parfois, on souhaite - tomber sur la donnée qui fait exploser la mémoire. - Le module `pympler `_ - propose quelques outils pour ces deux méthodes de diagnostic. - Quoiqu'il en soit, après une telle aventure, vous serez - probablement incité à écrire des petites fonctions facilement - testables séparéments plutôt que de grandes fonctions - terriblement compliquées à tester. diff --git a/_doc/sphinxdoc/source/blog/2018/2018-10-24_memory.rst b/_doc/sphinxdoc/source/blog/2018/2018-10-24_memory.rst deleted file mode 100644 index 92d5e9f6..00000000 --- a/_doc/sphinxdoc/source/blog/2018/2018-10-24_memory.rst +++ /dev/null @@ -1,20 +0,0 @@ - -.. blogpost:: - :title: Gestion de la mémoire en Python - :keywords: python, mémoire - :date: 2018-10-24 - :categories: mémoire - - La compréhension d'un langage compilé et bas niveau tel que le - :epkg:`C` aide énormément à comprendre pour :epkg:`Python` - est parfois très lent ou pourquoi il est en théorie un langage - multithreadé qui ne l'est pas en apparence. La vidéo suivante - explique d'autres petits recoins cachés du langage. - - .. youtube:: https://youtu.be/F6u5rhUQ6dU - - La suivante explique les désagréments que l'on rencontre souvent - quand un projet grossit inexorablement sans qu'on revisite - quelques vieux codes écrits par des auteurs parfois disparus. - - .. youtube:: https://youtu.be/JKYktDRoRxw diff --git a/_doc/sphinxdoc/source/blog/2020/2020-10-25_numpyinf.rst b/_doc/sphinxdoc/source/blog/2020/2020-10-25_numpyinf.rst deleted file mode 100644 index f76e3ff9..00000000 --- a/_doc/sphinxdoc/source/blog/2020/2020-10-25_numpyinf.rst +++ /dev/null @@ -1,43 +0,0 @@ - -.. blogpost:: - :title: Infinite dans une conversion de float64 en float32 - :keywords: python, mémoire - :date: 2020-10-25 - :categories: numpy - - C'est le genre de petits détails numériques qui font - qu'un calcul échoue sans qu'on se doute le plus souvent - qu'une erreur s'est glissée quelque part. - Le type `float32` est très utilisé dans le cas des réseaux - de neurones profonds car le calcul peut alors être fait - sur CPU et GPU. Dans le cas du machine learning classique, - avec :epkg:`scikit-learn`, c'est le type `float64` est qui - le plus souvent utilisé. Dès lors, il arrrive qu'on doivent - convertir des réels d'un type à l'autre. - - De `float32` à `float64`, tout se passe bien puisque le second - type est plus précis que le premier, il est codé sur plus d'octets. - Le nombre converti est identique à l'original dans ce cas. - Dans l'autre sens, on pourrait s'attendre à une légère perte - de précision, une sorte d'arrondi, sauf que dans un cas, - la différence est notable. - - .. runpython:: - :showcode: - - import numpy - x = numpy.float64(1e300) - print(x) - print(numpy.float32(x)) - - La valeur `1e300` ne peut être représentée avec un type - `float32 `_ - mais elle existe avec un type `float64`. Quand on - la convertit, :epkg:`numpy` la remplace par une constante - `numpy.inf `_ ce qui peut avoir un impact - assez grand selon les calculs qui suivent. - On pourrait que ce cas n'arrive pas souvent sauf quand on - utilise la fonction exponentielle. Et c'est très fréquent en - deep learning. diff --git a/_doc/sphinxdoc/source/c_lang/faq.rst b/_doc/sphinxdoc/source/c_lang/faq.rst deleted file mode 100644 index 56e05c48..00000000 --- a/_doc/sphinxdoc/source/c_lang/faq.rst +++ /dev/null @@ -1,16 +0,0 @@ - -.. _l-faq-python: - -=== -FAQ -=== - -.. contents:: - :local: - -FAQ -=== - -.. faqreflist:: - :tag: python - :contents: diff --git a/_doc/sphinxdoc/source/c_module/faq.rst b/_doc/sphinxdoc/source/c_module/faq.rst deleted file mode 100644 index 6ab13559..00000000 --- a/_doc/sphinxdoc/source/c_module/faq.rst +++ /dev/null @@ -1,10 +0,0 @@ - -.. _l-faq-module: - -=== -FAQ -=== - -.. faqreflist:: - :tag: module - :contents: diff --git a/_doc/sphinxdoc/source/conf.py b/_doc/sphinxdoc/source/conf.py deleted file mode 100644 index 3f31429d..00000000 --- a/_doc/sphinxdoc/source/conf.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -import sys -import os -import pydata_sphinx_theme -from pyquickhelper.helpgen.default_conf import set_sphinx_variables - -sys.path.insert(0, os.path.abspath(os.path.join(os.path.split(__file__)[0]))) -local_template = os.path.join(os.path.abspath( - os.path.dirname(__file__)), "phdoc_templates") - -set_sphinx_variables(__file__, "teachpyx", "Xavier Dupré", 2023, - "pydata_sphinx_theme", ['_static'], - locals(), extlinks=dict(issue=( - 'https://github.com/sdpython/teachpyx/issues/%s', - 'issue %s')), - title="Programmation avec le langage Python", book=True, nblayout='table') - -blog_root = "http://www.xavierdupre.fr/app/teachpyx/helpsphinx/" -extensions.append("sphinxcontrib.blockdiag") -# blockdiag_fontpath = '/usr/share/fonts/truetype/ipafont/ipagp.ttf' - -html_css_files = ['my-styles.css'] - -html_logo = "_static/project_ico_small.png" - -language = "fr" - -preamble = ''' -\\usepackage{etex} -\\usepackage{fixltx2e} % LaTeX patches, \\textsubscript -\\usepackage{cmap} % fix search and cut-and-paste in Acrobat -\\usepackage[raccourcis]{fast-diagram} -\\usepackage{titlesec} -\\usepackage{amsmath} -\\usepackage{amssymb} -\\usepackage{amsfonts} -\\usepackage{graphics} -\\usepackage{epic} -\\usepackage{eepic} -%\\usepackage{pict2e} -%%% Redefined titleformat -\\setlength{\\parindent}{0cm} -\\setlength{\\parskip}{1ex plus 0.5ex minus 0.2ex} -\\newcommand{\\hsp}{\\hspace{20pt}} -\\newcommand{\\acc}[1]{\\left\\{#1\\right\\}} -\\newcommand{\\cro}[1]{\\left[#1\\right]} -\\newcommand{\\pa}[1]{\\left(#1\\right)} -\\newcommand{\\R}{\\mathbb{R}} -\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}} -%\\titleformat{\\chapter}[hang]{\\Huge\\bfseries\\sffamily}{\\thechapter\\hsp}{0pt}{\\Huge\\bfseries\\sffamily} -''' - -custom_preamble = """\n -\\usepackage[all]{xy} -\\newcommand{\\vecteur}[2]{\\pa{#1,\\dots,#2}} -\\newcommand{\\N}[0]{\\mathbb{N}} -\\newcommand{\\indicatrice}[1]{\\mathbf{1\\!\\!1}_{\\acc{#1}}} -\\newcommand{\\infegal}[0]{\\leqslant} -\\newcommand{\\supegal}[0]{\\geqslant} -\\newcommand{\\ensemble}[2]{\\acc{#1,\\dots,#2}} -\\newcommand{\\fleche}[1]{\\overrightarrow{ #1 }} -\\newcommand{\\intervalle}[2]{\\left\\{#1,\\cdots,#2\\right\\}} -\\newcommand{\\loinormale}[2]{{\\cal N}\\pa{#1,#2}} -\\newcommand{\\independant}[0]{\\;\\makebox[3ex]{\\makebox[0ex]{\\rule[-0.2ex]{3ex}{.1ex}}\\!\\!\\!\\!\\makebox[.5ex][l]{\\rule[-.2ex]{.1ex}{2ex}}\\makebox[.5ex][l]{\\rule[-.2ex]{.1ex}{2ex}}} \\,\\,} -\\newcommand{\\esp}{\\mathbb{E}} -\\newcommand{\\var}{\\mathbb{V}} -\\newcommand{\\pr}[1]{\\mathbb{P}\\pa{#1}} -\\newcommand{\\loi}[0]{{\\cal L}} -\\newcommand{\\vecteurno}[2]{#1,\\dots,#2} -\\newcommand{\\norm}[1]{\\left\\Vert#1\\right\\Vert} -\\newcommand{\\norme}[1]{\\left\\Vert#1\\right\\Vert} -\\newcommand{\\dans}[0]{\\rightarrow} -\\newcommand{\\partialfrac}[2]{\\frac{\\partial #1}{\\partial #2}} -\\newcommand{\\partialdfrac}[2]{\\dfrac{\\partial #1}{\\partial #2}} -\\newcommand{\\loimultinomiale}[1]{{\\cal M}\\pa{#1}} -\\newcommand{\\trace}[1]{tr\\pa{#1}} -\\newcommand{\\sac}[0]{|} -\\newcommand{\\abs}[1]{\\left|#1\\right|} -""" -# \\usepackage{eepic} - -imgmath_latex_preamble = preamble + custom_preamble -latex_elements['preamble'] = preamble + custom_preamble -mathdef_link_only = True - -epkg_dictionary.update({ - 'algorithme': 'https://fr.wikipedia.org/wiki/Algorithme', - 'algorithmes numériques': - 'http://www.xavierdupre.fr/app/ensae_teaching_cs/helpsphinx3/' - 'specials/algorithm_culture.html#catalogue-d-algorithmes', - 'algorithmes de tri': 'https://fr.wikipedia.org/wiki/Algorithme_de_tri', - 'Anaconda': 'https://www.anaconda.com/', - 'Awesome Python': 'https://github.com/vinta/awesome-python', - 'C': 'https://fr.wikipedia.org/wiki/C_(langage)', - 'C++': 'https://fr.wikipedia.org/wiki/C%2B%2B', - 'cython': 'http://cython.org/', - 'format': 'https://docs.python.org/3/library/stdtypes.html#str.format', - 'joblib': 'https://pythonhosted.org/joblib/', - 'jupyter': 'https://jupyter.org/', - 'JSON': 'https://fr.wikipedia.org/wiki/JavaScript_Object_Notation', - 'Miniconda': 'https://docs.conda.io/en/latest/miniconda.html', - 'nan': 'https://docs.scipy.org/doc/numpy/reference/generated/numpy.isnan.html', - 'NaN': 'https://docs.scipy.org/doc/numpy/reference/generated/numpy.isnan.html', - 'OpenMP': 'https://fr.wikipedia.org/wiki/OpenMP', - 'programmation fonctionnelle': 'https://fr.wikipedia.org/wiki/Programmation_fonctionnelle', - 'programmation impérative': 'https://fr.wikipedia.org/wiki/Programmation_imp%C3%A9rative', - 'protobuf': 'https://developers.google.com/protocol-buffers/', - 'pyformat': 'https://pyformat.info/', - 'pypi': 'https://pypi.org/', - 'Python': 'https://www.python.org/', - 'shebang': 'https://fr.wikipedia.org/wiki/Shebang', - 'ujson': 'https://github.com/esnme/ultrajson', - 'ultrajson': 'https://github.com/esnme/ultrajson', - 'Visual Studio Code': 'https://code.visualstudio.com/', -}) diff --git a/_doc/sphinxdoc/source/doctestunit.rst b/_doc/sphinxdoc/source/doctestunit.rst deleted file mode 100644 index 4bbcef46..00000000 --- a/_doc/sphinxdoc/source/doctestunit.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _l-doctestunit: - -================================ -Documentation, unit tests, setup -================================ - -See `Unit tests with pyquickhelper `_. - -Extensions to install -===================== - -* `pyquickhelper `_ diff --git a/_doc/sphinxdoc/source/end_index2.rst b/_doc/sphinxdoc/source/end_index2.rst deleted file mode 100644 index 3ffbac49..00000000 --- a/_doc/sphinxdoc/source/end_index2.rst +++ /dev/null @@ -1,11 +0,0 @@ - -===== -Index -===== - -.. toctree:: - - filechanges - all_report - end_index_glossaire - blog/blogindex diff --git a/_doc/sphinxdoc/source/end_index_glossaire.rst b/_doc/sphinxdoc/source/end_index_glossaire.rst deleted file mode 100644 index 0340fe97..00000000 --- a/_doc/sphinxdoc/source/end_index_glossaire.rst +++ /dev/null @@ -1,19 +0,0 @@ - -====== -README -====== - -.. only:: html - - .. toctree:: - - glossary - README - license - -.. only:: not html - - .. toctree:: - - glossary - license diff --git a/_doc/sphinxdoc/source/glossary.rst b/_doc/sphinxdoc/source/glossary.rst deleted file mode 100644 index 59938190..00000000 --- a/_doc/sphinxdoc/source/glossary.rst +++ /dev/null @@ -1,31 +0,0 @@ - -.. index:: glossary - -======== -Glossary -======== - -.. glossary::>`_ - - cheatsheet - - Quelque chose comme pense-bête en français, - terme clé qui permet de retrouver des pages assez courtes qui - résume tout ce qu'il faut savoir sur un sujet précis comme - `Python 3 Cheat Sheet `_, - `Python For Data Science - A Cheat Sheet For Beginners `_. - La dernière est complète sur de nombreux sujets : - `Beginner's Python Cheat Sheet `_. - - format - - Le formatage de données est utilisé dès qu'une information est - affichée à l'écran, le plus souvent pour débugger ou pour logger. - Le site :epkg:`pyformat` recense différents usages utiles mais - parfois peu connus de la fonction :epkg:`format`. - - ml - Raccourci pour `Machine Learning `_. - - NLP - Raccourci pour `Natural Language Processing `_. diff --git a/_doc/sphinxdoc/source/i_examples.rst b/_doc/sphinxdoc/source/i_examples.rst deleted file mode 100644 index 125eed7b..00000000 --- a/_doc/sphinxdoc/source/i_examples.rst +++ /dev/null @@ -1,28 +0,0 @@ - -======== -Exemples -======== - -Exemples, FAQ (Frequently Asked Questions), notebooks -et autres petits bouts de codes qu'on espère pouvoir copier -coller sans les comprendre. Parfois c'est vrai. - -.. only:: html - - .. toctree:: - :maxdepth: 1 - - i_ex - i_faq - gyexamples/index - all_notebooks - -.. only:: latex - - .. toctree:: - :maxdepth: 2 - - i_ex - i_faq - gyexamples/index - all_notebooks diff --git a/_doc/sphinxdoc/source/i_faq.rst b/_doc/sphinxdoc/source/i_faq.rst deleted file mode 100644 index a29ee4d8..00000000 --- a/_doc/sphinxdoc/source/i_faq.rst +++ /dev/null @@ -1,48 +0,0 @@ - -.. _l-FAQ2: - -=== -FAQ -=== - -.. contents:: - :local: - -Langage Python -============== - -.. faqreflist:: - :contents: - :tag: python - -Classes -======= - -.. faqreflist:: - :contents: - :tag: class - -Modules -======= - -.. faqreflist:: - :contents: - :tag: module - -Manipulation de texte -===================== - -.. faqreflist:: - :contents: - :tag: regex - -Manipulation des données, calcul matriciel -========================================== - -.. faqreflist:: - :contents: - :tag: pandas - -.. faqreflist:: - :contents: - :tag: numpy diff --git a/_doc/sphinxdoc/source/i_index.rst b/_doc/sphinxdoc/source/i_index.rst deleted file mode 100644 index cbcc080b..00000000 --- a/_doc/sphinxdoc/source/i_index.rst +++ /dev/null @@ -1,21 +0,0 @@ - -===== -Index -===== - -.. only:: html - - .. toctree:: - :maxdepth: 1 - - defthe_index - end_index2 - blog/blogindex - -.. only:: latex - - .. toctree:: - :maxdepth: 2 - - end_index_glossaire - blog/blogindex diff --git a/_doc/sphinxdoc/source/index.rst b/_doc/sphinxdoc/source/index.rst deleted file mode 100644 index a3098fd7..00000000 --- a/_doc/sphinxdoc/source/index.rst +++ /dev/null @@ -1,91 +0,0 @@ - -*en construction permanente* - -.. |gitlogo| image:: _static/git_logo.png - :height: 20 - -====================================== -Apprendre la programmation avec Python -====================================== - -Internet est une source quasi-infinie de documents, papiers, bouts de -code sur beaucoup de sujets mais il faut savoir picorer. -Ce site se veut plus facile à lire de façon traditionnelle, -un peu comme un livre. Il s'adresse surtout à ceux qui ne savent -pas ou eu programmer. -Il est aussi disponible en -`PDF `_ -(format brut de fonderie) et sur -`GitHub/teachpyx `_ |gitlogo|. - -.. toctree:: - :maxdepth: 1 - - introduction - c_lang/index - c_classes/index - c_exception/index - c_module/index - c_regex/index - c_parallelisation/index - c_gui/index - c_data/index - i_examples - c_resume/index - i_index - -Les ordinateurs font principalement des calculs. Ils permettent -aussi d'automatiser de nombreuses tâches pour lesquelles ils -n'ont pas été spécifiquement conçus. Le site -`Xavier Dupré `_ -contient beaucoup d'exemples sur beaucoup de sujets, -souvent reliés au machine learning. - -.. only:: html - - .. image:: https://travis-ci.com/sdpython/teachpyx.svg?branch=master - :target: https://app.travis-ci.com/github/sdpython/teachpyx - :alt: Build status - - .. image:: https://ci.appveyor.com/api/projects/status/5jl303wl14dtesl0?svg=true - :target: https://ci.appveyor.com/project/sdpython/teachpyx - :alt: Build Status Windows - - .. image:: https://circleci.com/gh/sdpython/teachpyx/tree/master.svg?style=svg - :target: https://circleci.com/gh/sdpython/teachpyx/tree/master - - .. image:: https://badge.fury.io/py/teachpyx.svg - :target: https://pypi.org/project/teachpyx/ - - .. image:: https://img.shields.io/badge/license-MIT-blue.svg - :alt: MIT License - :target: http://opensource.org/licenses/MIT - - .. image:: https://codecov.io/github/sdpython/teachpyx/coverage.svg?branch=master - :target: https://codecov.io/github/sdpython/teachpyx?branch=master - - .. image:: http://img.shields.io/github/issues/sdpython/teachpyx.svg - :alt: GitHub Issues - :target: https://github.com/sdpython/teachpyx/issues - - .. image:: nbcov.png - :target: http://www.xavierdupre.fr/app/teachpyx/helpsphinx/all_notebooks_coverage.html - :alt: Notebook Coverage - - .. image:: https://img.shields.io/github/repo-size/sdpython/teachpyx - :target: https://github.com/sdpython/teachpyx/ - :alt: size - -+----------------------+---------------------+---------------------+--------------------+------------------------+------------------------------------------------+ -| :ref:`l-modules` | :ref:`l-functions` | :ref:`l-classes` | :ref:`l-methods` | :ref:`l-staticmethods` | :ref:`l-properties` | -+----------------------+---------------------+---------------------+--------------------+------------------------+------------------------------------------------+ -| :ref:`modindex` | :ref:`l-EX2` | :ref:`search` | :ref:`l-license` | :ref:`l-changes` | :ref:`l-README` | -+----------------------+---------------------+---------------------+--------------------+------------------------+------------------------------------------------+ -| :ref:`genindex` | :ref:`l-FAQ2` | :ref:`l-notebooks` | | :ref:`l-statcode` | `Unit Test Coverage `_ | -+----------------------+---------------------+---------------------+--------------------+------------------------+------------------------------------------------+ - -**Links:** `github `_, -`documentation `_, -:ref:`l-README`, -:ref:`blog `, -:ref:`l-issues-todolist` diff --git a/_doc/sphinxdoc/source/issues_todoextlist.rst b/_doc/sphinxdoc/source/issues_todoextlist.rst deleted file mode 100644 index 74a66423..00000000 --- a/_doc/sphinxdoc/source/issues_todoextlist.rst +++ /dev/null @@ -1,21 +0,0 @@ - -.. _l-issues-todolist: - -Bugs et améliorations -===================== - -.. index:: issues, todo - -.. contents:: - -Bugs -++++ - -.. todoextlist:: - :tag: bug - -Amélioration -++++++++++++ - -.. todoextlist:: - :tag: plus diff --git a/_doc/sphinxdoc/source/license.rst b/_doc/sphinxdoc/source/license.rst deleted file mode 100644 index d1a0e751..00000000 --- a/_doc/sphinxdoc/source/license.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _l-license: - -License -======= - -.. include:: LICENSE.txt - :literal: diff --git a/_doc/sphinxdoc/source/phdoc_templates/layout.html b/_doc/sphinxdoc/source/phdoc_templates/layout.html deleted file mode 100644 index 08baa3ec..00000000 --- a/_doc/sphinxdoc/source/phdoc_templates/layout.html +++ /dev/null @@ -1,5 +0,0 @@ -{# Import the theme's layout. #} -{% extends "!layout.html" %} - -{# Custom CSS overrides #} -{% set bootswatch_css_custom = ['_static/my-styles.css'] %} \ No newline at end of file diff --git a/_doc/sphinxdoc/source/phdoc_templates/my-styles.css b/_doc/sphinxdoc/source/phdoc_templates/my-styles.css deleted file mode 100644 index a51da6d8..00000000 --- a/_doc/sphinxdoc/source/phdoc_templates/my-styles.css +++ /dev/null @@ -1,30 +0,0 @@ -.admonition-mathdef { - color: #424242; - background-color: #F9F9F9; - font-size: 14px; -} -.admonition-todoext { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-faqref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-exref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-nbref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} -.admonition-blocref { - color: #424242; - background-color: #F9F9B9; - font-size: 14px; -} diff --git a/_doc/sphinxdoc/source/phdoc_templates/page.html b/_doc/sphinxdoc/source/phdoc_templates/page.html deleted file mode 100644 index 1be6020a..00000000 --- a/_doc/sphinxdoc/source/phdoc_templates/page.html +++ /dev/null @@ -1,4 +0,0 @@ -{% extends "layout.html" %} -{% block body %} -{{ body }} -{% endblock body %} diff --git a/_todo/chap6_module.tex b/_todo/chap6_module.tex deleted file mode 100644 index 1037d261..00000000 --- a/_todo/chap6_module.tex +++ /dev/null @@ -1,911 +0,0 @@ -\input{../../common/livre_begin.tex}% -\firstpassagedo{\input{python_cours_titre.tex}} -\input{../../common/livre_table_begin.tex}% -%\firstpassagedo{\input{python_cours_chapter.tex}} - - - - -%------------------------------------------------------------------------------------------------------------- -\chapter{Modules} -\label{chap_module} -%------------------------------------------------------------------------------------------------------------- - -Il est souvent prfrable de rpartir le code d'un grand programme sur plusieurs fichiers. Parmi tous ces fichiers, un seul est considr comme fichier principal, il contient son point d'entre, les premires instructions excutes. Les autres fichiers sont considrs comme des modules, en quelque sorte, des annexes qui contiennent tout ce dont le fichier principal a besoin. - - -\section{Modules et fichiers} - -\subsection{Exemple} - -\indexfr{module}\indexfr{point d'entre} -Cet exemple montre comment rpartir un programme sur deux fichiers. Le premier est appel \textit{module} car il n'inclut pas le point d'entre du programme. - - \begin{xdefinition}{point d'entre du programme} - Le point d'entre d'un programme est la premire instruction excute par l'ordinateur lors de l'excution - de ce programme. - \end{xdefinition} - -\indexkeyword{import}\indexmoduleund{import} -Cet exemple de module contient une fonction, une classe et une variable. Ces trois lments peuvent tre utiliss par n'importe quel fichier qui importe ce module. Le nom d'un module correspond au nom du fichier sans son extension. -\indexfrr{module}{nom} - -\begin{center}\begin{tabular}{@{}lr@{}} -\textbf{Fichier~: \codes{module\_exemple.py}} & \textbf{Fichier~: \codes{exemple.py}} \\ -\begin{minipage}{6.7cm} -\inputcodes{../python_cours/programme/module_exemple.py}{exemple de module}{} -\end{minipage} -& -\begin{minipage}{6.7cm} -\inputcodes{../python_cours/programme/exemple.py}{import de module}{ (1)} -\end{minipage} -\end{tabular} -\end{center} - - -Pour importer un module, il suffit d'insrer l'instruction \codes{import \; nom\_module} avant d'utiliser une des choses qu'il dfinit. Ces importations sont souvent regroupes au dbut du programme, elles sont de cette faon mises en vidence mme s'il est possible de les faire n'importe o. L'exemple ci-dessus droite importe le module dfini gauche. Les modules commencent le plus souvent par une chane de caractres comme dans l'exemple prcdent, celle-ci contient l'aide associe ce module. Elle apparat avec l'instruction \codes{help(module\_exemple)}. - -% -Rien ne diffrencie les deux fichiers \codes{module\_exemple.py} et \codes{exemple.py} except le fait que le second utilise des lments dfinis par le premier. Dans un programme compos de plusieurs fichiers, un seul contient le point d'entre et tous les autres sont des modules. - -La syntaxe d'appel d'un lment d'un module est identique celle d'une classe. On peut considrer un module comme une classe avec ses mthodes et ses attributs la seule diffrence qu'il ne peut y avoir qu'une seule instance d'un mme module. La rptition de l'instruction \codes{import \; module\_exemple} n'aura aucun effet~: un module n'est import que lors de la premire instruction \codes{import \; nom\_module} rencontr lors de l'excution du programme. - -\begin{xremark}{fichier \codes{*.pyc}} -L'utilisation d'un module qu'on a soi-mme conu provoque l'apparition d'un fichier d'extension~\codes{pyc}.\ifnotellipse{\indexfrr{extension de fichier}{pyc}}\indexfr{pyc}\indexfr{bytecode}Il correspond la traduction du module en \textit{bytecode} plus rapidement exploitable par l'interprteur \python. Ce fichier est gnr chaque modification du module. Lorsqu'un module est import, \pythons vrifie la date des deux fichiers d'extension \codes{py} et \codes{pyc}. Si le premier est plus rcent, le second est recr. Cela permet un gain de temps lorsqu'il y a un grand nombre de modules. Il faut faire attention lorsque le fichier source d'extension \codes{py} est supprim, il est alors encore possible de l'importer tant que sa version d'extension \codes{pyc} est prsente.\indexext{pyc}\indexext{py} -\end{xremark} - -\begin{xremark}{recharger un module} -Le module \codes{module\_exemple} contient une variable \codes{exemple\_variable} peut tre modifie au cours de l'excution du programme. Il est possible de revenir sa valeur initiale en forant \pythons recharger le module grce la fonction \codes{reload}.\indexfonction{reload}\vspaceneg\indexexemples{\codesindex{reload}}{} -\begin{verbatimx} -import module_exemple -module_exemple.exemple_variable = 10 -reload (module_exemple) -print module_exemple.exemple_variable # affiche 3 -\end{verbatimx} -\end{xremark} - - -\subsection{Autres syntaxes} - -Il existe trois syntaxes diffrentes pour importer un module. La premire est dcrite au paragraphe prcdent. Il en existe une autre qui permet d'affecter un module un identificateur diffrent du nom du fichier dans lequel il est dcrit. En ajoutant l'instruction \codes{as} suivi d'un autre nom \codes{alias}, le module sera dsign par la suite par l'identificateur \codes{alias} comme le montre l'exemple suivant. - -\textbf{Fichier~: \codes{exemple2.py}} \vspace{-0.3cm} -\inputcodes{../python_cours/programme/exemple2.py}{import de module}{ (2)} - -\indexkeyword{import}\indexkeyword{from}\indexkeyword{as}\indexfrr{module}{identificateur} -Une autre syntaxe permet de se passer d'identificateur pour un module en utilisant le mot-cl \codes{from}. En utilisant la syntaxe \codes{from \; module \; import \; *}, tous les identificateurs (fonctions, classes, variables) sont directement accessibles sans les faire prcder d'un identificateur de module ainsi que le montre l'exemple suivant. - -\textbf{Fichier~: \codes{exemple3.py}} \vspace{-0.3cm} -\inputcodes{../python_cours/programme/exemple3.py}{import de module}{ (3)} -% -La partie \codes{import \; *} permet d'importer toutes les classes, attributs ou fonctions d'un module mais il est possible d'crire \codes{from \; module\_exemple \; import \; exemple\_class} pour n'importer que cette classe. La fonction \codes{exemple\_fonction} ne sera pas accessible. Toutefois, cette syntaxe est dconseille. Elle rduit la longueur de certaines fonctions ou classes puisqu'il n'est plus besoin de faire apparatre le module d'o elle proviennent et cela ne permet plus de distinguer une classe ou une fonction dfinie dans ce fichier de celles dfinies dans un autre module import. - -Il existe une dernire syntaxe d'importation d'un module qui est utile quand on ne sait pas encore au moment d'criture du programme le nom du module importer. Celui-ci sera prcis l'aide d'une chane de caractres au moyen de la fonction \codes{\_\_import\_\_}.\indexfonction{\_\_import\_\_} - -\textbf{Fichier~: \codes{exemple4.py}} \vspace{-0.3cm} -\inputcodes{../python_cours/programme/exemple4.py}{import de module}{ (4)} - - - -\subsection{Nom d'un module} -\indexfrr{module}{nom} -Le nom d'un module est dfini par le nom du fichier sous lequel il est enregistr. Dans l'exemple du paragraphe prcdent, le module avait pour nom de fichier \codes{module\_exemple.py}, le nom de ce module est donc \codes{module\_exemple}. - -Nanmoins, ce module peut galement tre excut comme un programme normal. Si tel est le cas, son nom devient \codes{\_\_main\_\_}. C'est pourquoi, les quelques lignes qui suivent apparaissent souvent. Elles ne sont excutes que si ce fichier a pour nom \codes{\_\_main\_\_}. Un seul fichier peut porter ce nom~: celui qui contient le point d'entre. -\indexfr{point d'entre} -\indexoperateur{\_\_name\_\_}\indexfr{\codesindex{\_\_main\_\_}} -% -\indexexemples{\codesindex{\_\_name\_\_}}{} -\vspaceneg -\begin{verbatimx} -if __name__ == "__main__" : - print "ce fichier est le programme principal" -\end{verbatimx} -\vspaceneg -% -Cette astuce est rgulirement utilise pour tester les fonctions et classes dfinies dans un module. Etant donn que cette partie n'est excute que si ce fichier est le programme principal, ajouter du code aprs le test \codes{if \;\_\_name\_\_ == "\_\_main\_\_" :} n'a aucune incidence sur tout programme incluant ce fichier comme module. - -\subsection{Emplacement d'un module} -\indexfrr{module}{emplacement}\indexfrr{module}{rpertoire} -Lorsque le module est plac dans le mme rpertoire que le programme qui l'utilise, l'instruction \codes{import \; nom\_module\_sans\_extension} suffit. Cette instruction suffit galement si ce module est plac dans le rpertoire \codes{site-packages} prsent dans le rpertoire d'installation de \python. Si ce n'est pas le cas, il faut prciser l'interprteur \pythons o il doit chercher ce module~: -% -\vspaceneg -\indexexemples{\codesindex{sys.path}}{} -\begin{verbatimx} -import sys -sys.path.append (sys.path [0] + "/../common") -################ sys.path [0] = rpertoire de ce programme -import nom_module -\end{verbatimx} -\vspaceneg -% -La variable \codes{sys.path} contient les rpertoires o \pythons va chercher les modules. Le premier d'entre eux est le rpertoire du programme. Il suffit d'ajouter cette liste le rpertoire dsir, ici, un rpertoire appel \codes{common} situ au mme niveau que le rpertoire du programme. A ce sujet, il est conseill d'utiliser le plus souvent possible des chemins relatifs et non absolus\footnote{Depuis un rpertoire courant, les chemins relatifs permettent de faire rfrence d'autres rpertoires sans avoir prendre en compte leur emplacement sur le disque dur contrairement aux chemins absolus comme \httpstyle{C:/Python26/python.exe}.}. De cette faon, on peut recopier le programme et ses modules un autre endroit du disque dur sans altrer leur fonctionnement. \indexfr{chemin relatif, absolu}\indexfrr{module}{chemin relatif} - - -\subsection{Ajouter un module en cours d'excution} - -De la mme faon que \pythons est capable d'inclure de nouvelles portions de code en cours d'excution\footnote{grce la fonction \codesnote{exec}}, il est galement capable d'inclure en cours d'excution des modules dont on ne connat pas le nom au dbut de l'excution. Cela s'effectue grce la fonction \codes{\_\_import\_\_}\indexfonction{\_\_import\_\_} dj prsente ci-dessus. Nanmoins, cette fonction ne peut pas importer un module si celui-ci est dsign par un nom de fichier incluant son rpertoire. Il faut d'abord dterminer le rpertoire o est le module grce la fonction \codes{split}\indexfonction{split} du module \codes{os.path}.\indexmoduleint{os.path} Le programme suivant illustre cette possibilit en proposant une fonction qui importe un module connaissant le nom du fichier qui le contient. -% -\vspaceneg -\inputcode{../python_cours/programme/exemple_import.py}{import dynamique de module} - - -\subsection{Liste des modules imports} - -Le dictionnaire \codes{modules} du module \codes{sys}\indexmoduleint{sys} contient l'ensemble des modules imports. Le programme suivant affiche cette liste. -\vspaceneg -\indexexemples{liste des modules}{} -\begin{verbatimx} -import sys -for m in sys.modules : - print m, " " * (14 - len(str(m))), sys.modules [m] -\end{verbatimx} -\vspaceneg -% -\begin{verbatimx} -os -os.path -re -site -sys -types -... -\end{verbatimx} -\vspaceneg -% -Lorsque le programme stipule l'import d'un module, \pythons vrifie s'il n'est pas dj prsent dans cette liste. Dans le cas contraire, il l'importe. Chaque module n'est import qu'une seule fois. La premire instruction \codes{import \; module\_exemple} rencontre introduit une nouvelle entre dans le dictionnaire \codes{sys.modules}~: -% -\vspaceneg -\begin{verbatimx} -module_exemple -\end{verbatimx} -\vspaceneg -% -Le dictionnaire \codes{sys.modules} peut tre utilis pour vrifier la prsence d'un module ou lui assigner un autre identificateur. Un module est un objet qui n'autorise qu'une seule instance. -% -\vspaceneg -\indexexemples{existence d'un module}{} -\begin{verbatimx} -if "module_exemple" in sys.modules : - m = sys.modules ["module_exemple"] - m.exemple_fonction () -\end{verbatimx} - - -\subsection{Attributs communs tout module} - -Une fois imports, tous les modules possdent cinq attributs qui contiennent des informations comme leur nom, le chemin du fichier correspondant, l'aide associe. - -\begin{center}\begin{tabularx}{\textwidth}{|lX|} \hline -\codes{\_\_all\_\_} & Contient toutes les variables, fonctions, classes du module.\\ \hline -\codes{\_\_builtins\_\_} & Ce dictionnaire contient toutes les fonctions et classes inhrentes au langage \pythons - utilises par le module.\\ \hline -\codes{\_\_doc\_\_} & Contient l'aide associe au module.\\ \hline -\codes{\_\_file\_\_} & Contient le nom du fichier qui dfinit le module. Son extension est \codes{pyc}).\\ \hline -\codes{\_\_name\_\_} & Cette variable contient a priori le nom du module sauf si le module - est le point d'entre du programme auquel cas cette variable contient \codes{"\_\_main\_\_"}.\\ \hline -\end{tabularx}\end{center} -% -Ces attributs sont accessibles si le nom du module est utilis comme prfixe. Sans prfixe, ce sont ceux du module lui-mme. -% -\vspaceneg -\begin{verbatimx} -import os -print os.__name__, os.__doc__ -if __name__ == "__main__" : print "ce fichier est le point d'entre" -else : print "ce fichier est import" -\end{verbatimx} - -\subsection{Arborescence de modules, paquetage}\indexfrr{module}{arborescence}\indexfr{paquetage}\indexfrr{module}{paquetage} - -Lorsque le nombre de modules devient consquent, il est parfois souhaitable de rpartir tous ces fichiers dans plusieurs rpertoires. Il faudrait alors inclure tous ces rpertoires dans la liste \codes{sys.path} du module \codes{sys} ce qui parat fastidieux. \pythons propose la dfinition de paquetage, ce dernier englobe tous les fichiers \pythons d'un rpertoire condition que celui-ci contienne un fichier \codes{\_\_init\_\_.py} qui peut tre vide.\indexfr{\codesindex{\_\_init\_\_.py}}\indexmoduleund{\_\_init\_\_.py} La figure~\ref{pydoc_exemple_module_init_arbo} prsente une telle organisation et l'exemple suivant explicite comment importer chacun de ces fichiers sans avoir modifier les chemins d'importation. -% - \begin{figure}[ht] - \figureoneimage{ \caption{Arborescence de modules, un paquetage est dfini par un ensemble de fichiers - \pythons et d'un fichier \codescaption{\_\_init\_\_.py}. Les rpertoires sont grises tandis que les - fichiers apparaissent avec leur extension.} } - {\includegraphics[width=4.5cm]{\filextellipse{../python_cours/image/arbo}{../python_cours/image_ellipse/arbo}}} - {\label{pydoc_exemple_module_init_arbo}} - \end{figure} -% -\vspaceneg -\begin{verbatimx} -import mesmodules.extension -import mesmodules.part1.niveaudeux -import mesmodules.part2.niveaudeuxbis -\end{verbatimx} -\vspaceneg -% -Lors de la premire instruction \codes{import \; mesmodules.extension}, le langage \pythons ne s'intresse pas qu'au seul fichier \codes{extension.py}, il excute galement le contenu du fichier \codes{\_\_init\_\_.py}. Si cela est ncessaire, c'est ici qu'il faut insrer les instructions excuter avant l'import de n'importe quel module du paquetage. - - - - -\section{Modules internes} - -\pythons dispose de nombreux modules prinstalls\footnote{La page \httpstyle{http://docs.python.org/modindex.html} recense tous les modules disponibles avec \python.}. Cette liste est trop longue pour figurer dans ce document, elle est aussi susceptible de s'allonger au fur et mesure du dveloppement du langage \python. La table~\ref{module_utilise_table} (page~\pageref{module_utilise_table}) regroupe les modules les plus utiliss. - -\begin{table}[ht] -\begin{center}\begin{tabularx}{\textwidth}{|l|X|}\hline -\codes{calendar} & Grer les calendriers, les dates (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{calendar}}\\ \hline -\codes{cgi} & Utilis dans les scripts CGI (programmation Internet) \ifnotellipse{\indexmoduleint{cgi}}\\ \hline -\codes{cmath} & Fonctions mathmatiques complexes. \ifnotellipse{\indexmoduleint{cmath}}\\ \hline -\codes{codecs} & Jeux de caractres (voir paragraphe~\ref{para_cosedescodes}) \ifnotellipse{\indexmoduleint{codecs}}\\ \hline -\codes{copy} & Copies d'instances de classes. \ifnotellipse{\indexmoduleint{copy}}\\ \hline -\codes{csv} & Gestion des fichiers au format CSV (utiliss par \textit{Microsoft Excel}).\ifnotellipse{\indexoutil{Microsoft Excel}} \ifnotellipse{\indexmoduleint{csv}}\\ \hline -\codes{datetime} & Calculs sur les dates et heures (voir chapitre~\ref{chap_fichier}). \indexmoduleint{datetime}\\ \hline -\codes{gc} & Gestion du garbage collector. \ifnotellipse{\indexmoduleint{gc}}\\ \hline -\codes{getopt} & Lire les options des paramtres passs en arguments d'un programme \python. \ifnotellipse{\indexmoduleint{getopt}}\\ \hline -\codes{glob} & Chercher des fichiers (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{glob}}\\ \hline -\codes{hashlib} & Fonctions de cryptage. \ifnotellipse{\indexmoduleint{hashlib}}\\ \hline -\codes{htmllib} & Lire le format HTML. \ifnotellipse{\indexmoduleint{htmllib}}\\ \hline -\codes{math} & Fonctions mathmatiques standard telles que \codes{cos}, \codes{sin}, \codes{exp}, \codes{log}... \ifnotellipse{\indexmoduleint{math}}\indexfonction{cos}\indexfonction{sin}\indexfonction{log}\indexfonction{exp}\\ \hline -\codes{os} & Fonctions systmes dont certaines fonctions permettant de grer les fichiers (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{os}}\\ \hline -\codes{os.path} & Manipulations de noms de fichiers (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{os.path}}\\ \hline -\codes{pickle} & Srialisation d'objets, la srialisation consiste convertir des donnes structures de faon complexe en une structure linaire facilement enregistrable dans un fichier (voir chapitre~\ref{chap_fichier}). \indexmoduleint{pickle}\indexfr{srialisation}\\ \hline -\codes{profile} & Etudier le temps pass dans les fonctions d'un programme. \ifnotellipse{\indexmoduleint{profile}}\\ \hline -%\codes{pydoc} & Gnration de pages HTML contenant l'aide associe aux classes et aux fonctions d'un fichier. \indexmoduleint{pydoc}\\ \hline -\codes{random} & Gnration de nombres alatoires. \ifnotellipse{\indexmoduleint{random}}\\ \hline -\codes{re} & Expressions rgulires (voir paragraphe~\ref{regex_label_chap}). \ifnotellipse{\indexmoduleint{re}}\\ \hline -%\codes{sets} & Union, intersection d'ensembles. \indexmoduleint{sets}\\ \hline -\codes{shutil} & Copie de fichiers (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{shutil}}\\ \hline -\codes{sqlite3} & Accs aux fonctionnalits du gestionnaire de base de donnes SQLite3. \ifnotellipse{\indexmoduleint{sqlite3}}\ifnotellipse{\indexoutil{SQLite3}}\\ \hline -\codes{string} & Manipulations des chanes de caractres. \ifnotellipse{\indexmoduleint{string}}\\ \hline -\codes{sys} & Fonctions systmes, fonctions lies au langage \pythons (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{sys}}\\ \hline -\codes{threading} & Utilisation de threads (voir chapitre~\ref{chap_thread}). \ifnotellipse{\indexmoduleint{threading}}\\ \hline -\codes{time} & Accs l'heure, l'heure systme, l'heure d'une fichier. \ifnotellipse{\indexmoduleint{time}}\\ \hline -\codes{Tkinter} & Interface graphique (voir chapitre~\ref{chap_interface}). \ifnotellipse{\indexmoduleint{Tkinter}}\\ \hline -\codes{unittest} & Tests unitaires (ou comment amliorer la fiabilit d'un programme).\ifnotellipse{\indexmoduleint{unittest}}\\ \hline -\codes{urllib} & Pour lire le contenu de page HTML sans utiliser un navigateur. \ifnotellipse{\indexmoduleint{urllib}}\\ \hline -\codes{urllib2} & Module plus complet que \codes{urllib}. \ifnotellipse{\indexmoduleint{urllib2}}\\ \hline -\codes{xml.dom} & Lecture du format XML. \ifnotellipse{\indexmoduleint{xml.dom}}\\ \hline -\codes{xml.sax} & Lecture du format XML. \ifnotellipse{\indexmoduleint{xml.sax}}\\ \hline -\codes{zipfile} & Lecture de fichiers ZIP (voir chapitre~\ref{chap_fichier}). \ifnotellipse{\indexmoduleint{zipfile}}\\ \hline -\end{tabularx}\end{center} -\label{module_utilise_table} -\caption{Liste de modules souvent utiliss. La liste exhaustive est disponible l'adresse - \httpstyle{http://docs.python.org/modindex.html}. Les moteurs de recherche sur Internet retournent - des rsultats assez pertinents sur des requtes du type \textit{python + le nom du module}. - Les rsultats sont principalement en langue anglaise.} -\end{table} - -\ifnotellipse{ -Certains de ces modules sont prsents dans les chapitres qui suivent. Le programme suivant par exemple utilise les modules \codes{random} et \codes{math} pour estimer le nombre \codes{pi}. Pour cela, on tire alatoirement deux nombres $\pa{x,y}$ dans l'intervalle $\cro{0,1}$, si $\sqrt{x^2+y^2} \infegal 1$, on compte~1 sinon~0. Au final, $\hat{\pi} = \esp{\indicatrice{\sqrt{x^2+y^2} \infegal 1}}$. -% -\inputcode{../python_cours/programme/pi.py}{estimation du nombre $\pi$} -} - -Le programme suivant calcule l'intgrale de Monte Carlo\indexfr{Monte Carlo} de la fonction $f(x)=\sqrt{x}$ qui consiste tirer des nombres alatoires dans l'intervalle \codes{a,b} puis faire la moyenne des $\sqrt{x}$ obtenu. -% -\inputcode{../python_cours/programme/integrale.py}{intgrale de Monte Carlo} -% -Le programme suivant utilise le module \codes{urllib}\indexmoduleint{urllib} pour tlcharger le contenu d'une page et l'afficher. -\vspaceneg -\indexexemples{lecture d'une page HTML}{} -\begin{verbatimx} -def get_page_html (url): - import urllib - d = urllib.urlopen(url) - res = d.read () - d.close () - return res - -url = "http://www.lemonde.fr" -print get_page_html (url) -\end{verbatimx} -\vspaceneg - -\if 0 - -\section{Gnration automatique de la documentation} \label{generation_autoamtidqsdlfqlsd_fgqsdfq} - -Le langage \pythons permet d'associer de la documentation chaque lment du programme (fonction, classe, mthode, modules). Elle est accessible en tapant l'instruction \codes{help (...)} avec comme argument l'lment dont on veut lire la documentation. Cette lecture n'est pas forcment facile, c'est pourquoi il peut tre utile de gnrer une page HTML avec le contenu de cette aide. Il suffit pour cela d'crire dans une fentre commande en remplaant \codes{nom\_de\_fichier} par le nom d'un programme \pythons sans son extension. \indexoutil{pydoc} -\vspaceneg -\indexexemples{ligne de commande}{} -\begin{verbatimx} -c:\python26\python c:\python26\lib\pydoc.py -w nom_de_fichier -\end{verbatimx} -\vspaceneg -% -L'autre solution est d'utiliser la fonction \codes{pydoc\_generation} dfinie dans l'exemple suivant. Cette fonction gnre l'aide depuis un programme \pythons en excutant une instruction en ligne de commande grce la fonction \codes{system} du module \codes{os}.\indexmoduleint{os}\indexfonction{system} Le rsultat obtenu est prsent par la figure~\ref{pydoc_exemple_module_ref}. -% -\label{exemple_programme_pydoc_module} -\inputcode{../python_cours/programme/exemple_pydoc.py}{gnration automatique de l'aide avec \codesindex{pydoc}} -% - \begin{figure}[ht] - \figureoneimage{ \caption{Page HTML gnre par l'outil \codescaption{pydoc}, cette page correspond - au programme de la page~\pageref{exemple_programme_pydoc_module}. Elle est divise en trois parties, - la premire fait rfrence aux modules inclus, la seconde aux classes qui y sont dfinies, la troisime - aux fonctions.} } - {\includegraphics[width=6.5cm]{\filextellipse{../python_cours/image/pydoc_image} - {../python_cours/image_ellipse/pydoc_image}} } - \label{pydoc_exemple_module_ref} - \end{figure} - -\fi - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Modules externes} -\indexfrr{module}{externe} - -Les modules externes ne sont pas fournis avec \python, ils ncessitent une installation supplmentaire. Il serait impossible de couvrir tous les thmes abords par ces extensions. La simplicit d'utilisation du langage \pythons et son interfaage facile avec le langage~\textit{C} contribue sa popularit. Il permet de relier entre eux des projets conus dans des environnements diffrents, dans des langages diffrents. Depuis les versions 2.3, 2.4 du langage \python, la plupart des modules externes sont faciles installer, faciles utiliser d'aprs les exemples que fournissent de plus en plus les sites Internet qui les hbergent. De plus, il s'coule peu de temps entre la mise disposition d'une nouvelle version du langage \pythons et la mise jour du module pour cette version\footnote{Ceci n'est pas tout--fait vrai pour la version~3.0 du langage dont les changements sont trop consquents. Un changement du premier numro de version indique souvent des changements majeurs.}. Le paragraphe~\ref{mosule_dexifsqlliste} (page~\pageref{mosule_dexifsqlliste}) donne une liste de modules utiles du point de vue d'un ingnieur gnraliste. - -Nanmoins, de nombreux modules ont t conus pour un besoin spcifique et ne sont plus maintenus. Cela convient lors de l'criture d'un programme qui remplit un besoin ponctuel. Pour une application plus ambitieuse, il est ncessaire de vrifier quelques informations comme la date de cration, celle de la dernire mise jour, la prsence d'une documentation, une prvision pour la sortie de la future version, si c'est une personne lambda qui l'a conu ou si c'est une organisation comme celle qui fournit le module \codes{pygoogledesktop}\footnote{\httpstyle{http://code.google.com/p/pythongoogledesktop/}}.\ifnotellipse{\indexmoduleext{pygoogledesktop}} C'est le cas de tous les modules prsents au pragraphe~\ref{mosule_dexifsqlliste}. - -Concernant leur installation, certains modules externes comme \codes{SciPy} peuvent tre installs l'aide d'un fichier excutable sous \textit{Windows}. Il suffit d'excuter ce fichier pour pouvoir se servir du module par la suite dans un programme \python. Ce mode d'installation est disponible pour la plupart des modules de taille consquente. - -D'autres modules apparaissent compresss dans un fichier. Une fois dcompresss, ils incluent un fichier \codes{setup.py}. Le langage \pythons fournit une procdure d'installation standard~: il suffit d'crire quelques lignes dans une fentre de commande ouverte dans le rpertoire o a t dcompress le fichier contenant le module installer. -% -\vspaceneg -\indexexemples{installation d'un module}{} -\begin{verbatimx} -c:\python26\python setup.py install -\end{verbatimx} -\vspaceneg -% -Sous \textit{Linux} et \textit{Mac~OS~X}, cette ligne devient~: -\vspaceneg -\begin{verbatimx} -python setup.py install -\end{verbatimx} - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{\Pythons et les autres langages} - -Il est impossible d'obtenir avec le mme langage la fois une grande vitesse de dveloppement et une grande vitesse d'excution. La faon dont est gre la mmoire est un lment important qui explique l'appartenance d'un langage l'une ou l'autre des deux catgories. \pythons inclut une fonctionnalit qu'on appelle le \emph{garbage collector}. \indexfr{garbage collector} A chaque objet cr correspond un emplacement mmoire. Celui-ci peut tre cr et dtruit de faon explicite ou tre totalement gr par le langage, ce que fait \python. Il est inutile de se soucier d'un objet dont on ne sert plus, il sera dtruit automatiquement et la place mmoire qu'il utilisait sera de nouveau exploitable. Cette aisance de programmation suppose que le langage sache dterminer avec exactitude quand une variable n'est plus utilise. Ceci signifie que \pythons mmorise des informations supplmentaires sur tous les objets crs en cours d'excution pour assurer leur rfrencement. \pythons est tout moment en mesure de connatre l'ensemble des noms de variables utiliss pour dsigner le mme objet. Le \emph{garbage collector} alourdit un programme de faon cache, il le ralentit tout en facilitant la conception des programmes. - -\indexfr{vitesse d'excution} -C'est pour acclrer l'excution que le langage \pythons est parfois associ d'autres langages. Le programme final crit en \pythons utilise des fonctionnalits haut niveau codes dans un autre langage plus rapide. - - - -\subsection{Langage \textit{Java}}\indexlangage{Java} - -Il est possible d'utiliser des classes \textit{Java} en \python. Cette possibilit ne sera pas plus dtaille ici car le langage \textit{Java} est galement un langage interprt mme s'il est nettement plus rapide. Pour cela, il faut utiliser une version de l'interprteur \pythons code lui-mme en \textit{Java} ce qui est le cas de la version \textit{Java} de \python~: \emph{Jython}\footnote{\httpstyle{http://www.jython.org/Project/}}.\indexoutil{Jython}\indexfr{Java} - - -\subsection{Langage \textit{C}}\indexfr{\textit{C, C++}}\indexlangage{C, C++} - -Il existe deux faons de construire un programme mlant \pythons et langage~\textit{C}. La premire mthode est la ralisation de modules \pythons crits en~\textit{C} ou~\textit{C++}. A moins de devoir construire un module le plus efficace possible, il est peu conseill de le faire directement car cela implique de grer soi-mme le rfrencement des variables cres en~\textit{C} ou~\textit{C++} et exportes vers \python\footnote{Il faut tenir compte dans le module en \textit{C} des oprations ncessaires au garbage collector.}. Il est prfrable d'utiliser des outils comme la librairie \textit{SWIG}\footnote{\httpstyle{http://www.swig.org/}},\ifnotellipse{\indexoutil{SWIG}}ou encore la librairie \textit{Boost Python}\footnote{\httpstyle{http://www.boost.org/doc/libs/1\_36\_0/libs/python/doc/index.html}} qui simplifie le travail d'intgration.\indexoutil{Boost Python} C'est cette dernire option qui est dtaille dans ce livre. - -L'utilisation d'un autre langage est en effet indispensable lorsque l'exigence de rapidit est trop grande. Les modules scientifiques tels que \codes{scipy} ou \codes{numpy} ne rpondent pas tous les besoins. Il faut parfois dvelopper soi-mme des outils numriques en \textit{C++}\footnote{en finance par exemple} mme si la partie interface est assure par \python. - -L'autre faon de mlanger les deux langages est l'inclusion de petites parties~\textit{C} dans un programme \python. Ce point a dj t voqu au paragraphe~\ref{accelation_pyrex_weave} (page~\pageref{accelation_pyrex_weave}). Cela permet une optimisation essentiellement locale et numrique mais pas l'utilisation sous \pythons d'un projet existant programm en~\textit{C++} ou~\textit{C}. Sous \textit{Microsoft Windows}, il existe galement une version du langage \textit{IronPython}\footnote{\httpstyle{http://ironpython.net/}} dveloppe pour ce systme d'exploitation. L'intgration des DLL y est plus facile. - -D'une manire gnrale, il est prfrable de scinder nettement les parties d'un mme programme qui s'occupent de calculs numriques de celles qui prennent en charge l'interface graphique. Construire un module crit en \textit{C++} pour grer les calculs numriques est une faon drastique et efficace d'oprer cette scission. - - -%------------------------------------------------------------------------------------------ -\ifnotellipse{ - -\section{Ecrire un module en langage~\textit{C++}} -\indexlangage{C++}\indexfr{garbage collector} - -Avant de dcrire la librairie \textit{Boost Python} qui facilite l'criture d'extension en langage~\textit{C++}, il peut tre utile de voir un exemple d'un module crit dans ce langage. L'inconvnient majeur est le comptage des rfrences~: le garbage collector du langage \python dtruit automatique toute variable qui n'est plus utilise. Cette information est gre automatiquement par le langage \python mais doit l'tre manuellement au sein des extensions crites en langage~\textit{C++}. - -Un pralable est cependant ncessaire pour les utilisateurs du systme d'exploitation \textit{Windows}. Il faut que le compilateur \textit{MinGW}\footnote{\httpstyle{http://www.mingw.org/}}\indexoutil{MinGW} soit install. C'est l'adaptation du compilateur~\textit{C++} \textit{gcc}\indexoutil{gcc} qui est prsent sur tout systme d'exploitation \textit{Linux}. - -L'exemple suivant~: - -\inputcode{../python_cours/programme/sample_module.cpp}{un module en C++} - -Le module suivant vite l'installation manuelle d'un module crit en \textit{C++}. Il dtecte que le module a t modifi et qu'il doit tre recompil. Toutefois, il ne gre qu'un seul fichier. - -\inputcode{../python_cours/programme/import_c_module.py}{importer un module en C++} - -} % ifnotellipse - -%------------------------------------------------------------------------------------------ - -\section{\textit{Boost Python}} \label{boost_python_section_ok}\indexoutil{Boost Python} - -La librairie \emph{Boost}\footnote{\httpstyle{http://www.boost.org/}}\indexoutil{Boost} est une librairie crite en C++ qui a l'avantage d'tre portable~: elle est utilisable sur les systmes d'exploitation les plus courants. \indexfr{portable} Rgulirement mise jour, elle propose une extension de la librairie \emph{Standard Template Library (STL)} incluant notamment les expressions rgulires, les graphes, les threads,~...\indexoutil{Standard Template Library (STL)} \textit{Boost Python} est une partie de cette librairie qui se prsente galement sous forme de \emph{template}\footnote{Les \textit{template} ou \textit{patron de classe}\indexfr{patron de classe} sont un concept de mtaprogrammation.\ifnotellipse{\indexfr{mtaprogrammation}}Lorsque deux classes sont presque identiques l'exception d'un type, le langage \textit{C++} autorise la cration d'un patron unique pour ces deux classes. Le \textit{C++} est typage statique~: il faut crire deux classes pour crer un tableau d'entiers et un tableau de rels mme si le code est le mme. Les \textit{template} permettent de factoriser le code de ces deux classes.}.\indexfr{template} - -Il est prfrable d'avoir programm en \textit{C++} et en \pythons pour pouvoir mettre en \oe uvre les exemples proposs ci-dessous. -La prise en main ncessite un investissement, une certaine habitude des longs messages d'erreurs issus des \emph{template} mais une fois que cela est fait, la librairie acclre notablement l'criture d'un module. Il n'est plus utile de se soucier de l'interfaage avec \pythons et notamment du rfrencement drfrencement des objets pour le \emph{garbage collector}\footnote{Le langage \pythons dtruit automatique les objets qui ne sont plus utiliss. Cette fonctionnalit s'appuie sur un rfrencement de tous les objets crs. Alors qu'il est implicite en \python, il est explicite dans un module \pythons crit en langage~\textit{C} moins d'utiliser une librairie comme \textit{Boost Python} qui prend en charge une partie de cette tche (voir la page \httpstyle{http://docs.python.org/c-api/intro.html\#objects-types-and-reference-counts}).}. \indexfr{garbage collector} - -\begin{xremark}{utilisation d'un logiciel de suivi de source} -Le nombre de fichiers est assez important, il est conseill de conserver l'historique des modifications grce un logiciel de suivi de source tels que \textit{TortoiseSVN}\footnote{\httpstyle{http://tortoisesvn.tigris.org/}}. Cela vite de perdre parfois une demi-journe de travail. -\end{xremark} - -\subsection{Exemple}\label{python_boost_exemple} - -Vous pourrez trouver l'adresse suivante\footnote{\httpstyle{http://www.xavierdupre.fr/}} l'ensemble des sources ncessaires la ralisation d'un module avec \textit{Boost Python}\footnote{L'adresse suivante fournit une aide plus complte que ce document~: \httpstyle{http://www.boost.org/libs/python/doc/tutorial/doc/html/index.html}.}. Ce projet est configur pour \emph{Microsoft Visual Studio C++} \indexoutil{Microsoft Visual Studio C++} et dfinit un premier module appel \emph{PythonSample} qui contient quelques fonctions et une classe. Le rsultat est une DLL (Dynamic Link Library)\indexfr{Dynamic Link Library (DLL)} qui sera appele par le langage \python. Cet exemple est conu pour \textit{Windows}. - -Un point important est l'utilisation de la librairie \codes{c:\backslash python26\backslash python26.lib} qui explique qu'un module compil pour une version donne de \pythons ne puisse tre utilis avec une autre version~: un module compil avec la version~2.4 ne fonctionnera pas avec la version~2.6. - -L'exemple propos contient galement diffrentes fonctions de conversion des structures \pythons vers des containers de la \textit{STL} ou \textit{Standard Template Library}. Il suffit d'ouvrir le fichier \codes{pythonsample.sln} avec \textit{Microsoft Visual~C++} pour avoir accs au code source, c'est ce que montre la figure~\ref{boost_scheme_module_visual}. Le fichier \codes{exesample.sln} dfinit un programme excutable permettant de tester le module sans \pythons (voir figure~\ref{boost_scheme_module}). Les paragraphes qui suivent prsentent quelques lments de syntaxe et se concluent par un exercice qui consiste ajouter une fonction au module. - - - \begin{figure}[ht] - \figureoneimage{ \caption{Copie d'cran du projet ouvert avec \textit{Microsoft Visual~C++}. Les deux projets - \codescaption{dllc \; boost\_python} et \codescaption{lib\_in\_dll \; boost} contiennent les sources - \textit{Boost Python}. Le projet \codescaption{lib\_in\_dll \; libsample} contient le code d'une librairie - qui est crite sans tenir compte du fait que celle-ci sera utilise sous forme de module \python. - Le dernier projet \codescaption{dllc \; pythonsample} ajoute la couche qui fera le pont entre la librairie - \codescaption{libsample} et le langage \python. Les fichiers \codescaption{conversion.*} - contiennent des fonctions de conversion des types \pythons vers des types \textit{C++} ou plus - prcisment de la STL (Standard Template Library). Le fichier \codescaption{definition.cpp} - contient le point d'entre du module~: la macro \codescaption{BOOST\_PYTHON\_MODULE} qui - dclare \pythons les fonctions et classes du module. \vspace{-1cm} } } - {\includegraphics[width=6cm]{\filextellipse{../python_cours/image/boost} - {../python_cours/image_ellipse/boost}} } - {\label{boost_scheme_module_visual}} - \ifnotellipse{\indexfr{STL}\indexfr{Standard Template Library}} - \end{figure} - - - -\subsection{Les grandes lignes} - -Un module construit avec \textit{Boost Python} se compose de trois lments, une inamovible DLL \codes{boost\_python.dll}, un fichier \texttt{.py} portant le nom du module, une DLL \texttt{.dll}. Les deux premiers fichiers ne changent pas, le dernier contient les classes et fonctions proposes par le module. L'organisation propose dans l'exemple du paragraphe~\ref{python_boost_exemple} suit le schma de la figure~\ref{boost_scheme_module}. L'utilisation d'un programme excutable n'est pas indispensable. Toutefois, cela permet de tester le module sans \pythons et ainsi de faciliter sa conception. - - - - \begin{figure}[ht] - \figureoneimage{ \caption{Schma gnral de l'exemple introduit au paragraphe~\ref{python_boost_exemple}. - Le code de la librairie est utilis selon deux faons, l'intrieur d'un module \pythons - ce qui est l'objectif recherch et l'intrieur d'un programme excutable utilis - pour tester cette librairie sans passer par \python.} \vspace{-1cm} } - {\includegraphics[width=7cm]{\filextellipse{../python_cours/image/boostp} - {../python_cours/image_ellipse/boostp}} } - {\label{boost_scheme_module}} - \end{figure} - -Une fois le module prt, il est utilisable dans tout programme \python. Il suffit de l'importer. Lors de cette tape, une fonction va tre excute pour indiquer au langage \pythons l'ensemble des classes et des fonctions prsentes dans le module. - - -\subsubsection{Initialiser le module} - -L'initialisation d'un module correspond la dclaration au langage \pythons de l'ensemble des classes et des fonctions exporter. Cette partie peut contenir des tches qui doivent tre faites la premire fois que \pythons importe le module (initialisation de variables globales par exemple, chargement de donnes,~...). L'objectif de cette initialisation est de construire pour chaque fonction ou classe ou mthode un objet \pythons correspondant. \indexboost{BOOST\_PYTHON\_MODULE} -\vspaceneg -\begin{verbatimx} -BOOST_PYTHON_MODULE(PythonSample) -{ - // tapes d'initialisation -} ; -\end{verbatimx} - - -\subsubsection{Ajout d'une fonction} -\indexboost{boost::python::def} -La fonction \codes{boost::python::def} permet de dclarer une fonction. On peut y prciser les arguments, des valeurs par dfaut, un message d'aide retourn par l'instruction \pythons \codes{help}. -\vspaceneg -\begin{verbatimx} -int fonction (int r, const char * s, double x = 4) ; -BOOST_PYTHON_MODULE(PythonSample) -{ - boost::python::def ("fonction", fonction, - (boost::python::arg ("r"), - boost::python::arg ("s"), - boost::python::arg ("x") = 4), - "aide associe la fonction") ; -} ; -\end{verbatimx} -\vspaceneg -Les arguments de \codes{boost::python::def} sont les suivants~: - -\begin{small} -\begin{enumerate} -\item Le premier argument est le nom de la fonction exporte en \python. Ce nom peut tout fait tre diffrent de celui de la fonction \textit{C++}. -\item Le second argument est la fonction elle-mme. -\item Le troisime argument est la liste des arguments suivis ou non d'une valeur par dfaut. -\item Le dernier argument est l'aide associe la fonction. -\end{enumerate} -\end{small} - -Ct \python, cela donne~: -\vspaceneg -\begin{verbatimx} -import PythonSample -print PythonSample.fonction (4, "second") -print PythonSample.fonction (4, "second", 5) -\end{verbatimx} -\vspaceneg - -La surcharge de fonction est possible avec \textit{Boost Python} mais elle ne sera pas dtaille ici. Le langage \pythons n'autorise pas la surcharge, la rendre possible revient crer une fonction qui appellera telle ou telle autre fonction selon le type et le nombre des paramtres qu'elle aura reus. - - - - -\subsubsection{Ajout d'une classe} - -La dclaration d'une classe suit le mme schma que pour une fonction mais avec le template \codes{boost::python::class\_}. \indexboost{boost::python::class\_} Lorsque le constructeur n'a pas d'argument, la dclaration suit le schma suivant~: -\vspaceneg -\begin{verbatimx} - boost::python::class_ obj ( - "ClassSample", - "help on PythonClassSample") ) ; -\end{verbatimx} -\vspaceneg -% -Le template \codes{class\_} est instanci sur la classe exporter, ici \codes{PythonClassSample}. On cre un objet \codes{obj} de type \codes{boost::python::class\_}. Son constructeur prend comme arguments~: - -\begin{small} -\begin{enumerate} -\item Le nom de la classe en \python. -\item L'aide qui lui est associe. Ce second paramtre est facultatif mais il est conseill de le renseigner. -\end{enumerate} -\end{small} -% -Au cas o la classe aurait un constructeur avec des paramtres, il faudrait ajouter le code suivant~: \indexboost{boost::python::init} -\vspaceneg -\begin{verbatimx} - boost::python::class_ obj ( - "ClassSample", - "help on PythonClassSample", - boost::python::init ( // ajout - (boost::python::arg ("a"), // ajout - boost::python::arg ("s") = "default value for s"), // ajout - "help on PythonClassSample constructor" ) // ajout - ) ; -\end{verbatimx} -\vspaceneg -C'est--dire un autre template \codes{boost::python::init<...>} dont les arguments sont les types des paramtres du constructeur, c'est--dire entier et chane de caractres dans l'exemple prcdent. La suite est identique la dclaration d'une fonction. Il est galement possible de dfinir un hritage de la manire qui suit~: -\vspaceneg -\begin{verbatimx} - boost::python::class_ > obj ( - "ClassSample", - "help on PythonClassSample") ; -\end{verbatimx} -\vspaceneg -Le template \codes{class\_}\indexboost{boost::python::bases} peut recevoir un autre argument qui est \codes{boost::python::bases} avec \codes{ClassBase} dsignant la classe mre de la classe dclare. Cette dernire doit avoir t dclare au pralable avec cette mme syntaxe \codes{boost::python::class\_}. -\vspaceneg -\begin{verbatimx} - boost::python::class_ > obj ( - // ... -\end{verbatimx} -\vspaceneg -% -\begin{xremark}{template \textit{C++}} -Lorsqu'un template est un argument d'un autre template, il faut insrer un espace entre deux symboles \codes{<} ou \codes{>} conscutifs pour viter la confusion avec les oprateurs~\texttt{<}\texttt{<} ou~\texttt{>}\texttt{>} qui existent en \textit{C++}. -\end{xremark} - -\subsubsection{Ajout d'une mthode} - -La dclaration d'une classe passe par la dclaration d'une instance du template \codes{class\_}. Dans les exemples utiliss, cette instance porte le nom \codes{obj}. C'est cette instance qui va permettre de dclarer une mthode exactement de la mme manire qu'une fonction~: -\vspaceneg -\begin{verbatimx} - obj.def ( "Random", - &PythonClassSample::Random, - (boost::python::arg ("pos")), - "help on the method") ; -\end{verbatimx} -\vspaceneg -Cette mme mthode \codes{def} permet galement de surcharge le constructeur au cas o la classe pourrait tre initialise de diffrentes manires. Cela donne~: \indexboost{def} -\vspaceneg -\begin{verbatimx} - boost::python::class_ obj ("Vector", "help on vector", - boost::python::init ( - (PY_ARG ("n")), - "cre un vecteur de dimension n")) ; - // ajout d'un constructeur sans paramtre - obj.def (boost::python::init ()) ; -\end{verbatimx} -\vspaceneg -La classe \pythons \codes{Vector} peut tre cre avec un ou aucun paramtre~: -\vspaceneg -\begin{verbatimx} -v = PythonSample.Vector () -v2 = PythonSample.Vector (10) -\end{verbatimx} - -\subsubsection{Ajout d'un attribut} - -La dclaration \indexboost{def\_readwrite} d'un attribut s'effectue avec la mthode \codes{def\_readwrite}~: -\vspaceneg -\begin{verbatimx} - obj.def_readwrite ("a", &PythonClassSample::_a, "retourne un accs a") ; -\end{verbatimx} -\vspaceneg -Le premier paramtre sera son nom sous \python, le second le paramtre lui-mme, le troisime l'aide associe. La mthode \codes{def\_readwrite} permet d'exporter un attribut de sorte qu'il soit lisible et modifiable. - - - - - -\subsection{Exemple concret~: ajout d'une fonction} - -L'objectif est d'ajouter une fonction au module. La premire tape consiste dcompresser le fichier tlcharg\footnote{depuis l'adresse \httpstyle{http://www.xavierdupre.fr/}}, compiler l'ensemble des fichiers sous \textit{Microsoft Visual~C++} en version \textit{release} et \textit{debug}. L'excution du programme \codes{PythonSample/test/test.py} doit s'effectuer sans problme. Ajouter une fonction revient ensuite suivre les tapes suivantes~: - -\begin{small} -\begin{enumerate} -\item Dclarer la fonction dans le fichier \codesmall{libSample/mafonction.h} qu'on cre. -\item Implmenter la fonction dans le fichier \codesmall{libSample/mafonction.cpp} qu'on cre galement. -\end{enumerate} -\end{small} - -La partie purement \textit{C++} est termine\footnote{C'est facultatif mais il est galement conseill d'crire d'crire un code pour tester cette fonction dans le fichier \codesnote{exeSample/source/main.cpp}. Cela rduit le risque d'erreurs d'excution dans cette partie.}, il faut maintenant dfinir la transition \textit{C++}$\rightarrow$\pythons grce aux tapes suivantes~: - -\begin{small} -\begin{enumerate} -\item On dclare une fonction dans un fichier \codesmall{PythonSample/mafonction.h} qu'on cre. Elle peut par exemple porter le mme nom que la prcdente mais prfix par \codesmall{python\_}. -\item On peut passer l'implmentation de la fonction \pythons dans un fichier \codesmall{PythonSample/mafonction.cpp} qu'on cre aussi. Le code est sensiblement le mme pour chaque fonction ajoute~: il faut convertir les paramtres depuis des structures \pythons en type \textit{C++}, appeler la fonction \textit{C++} puis effectuer la conversion inverse. On pourra s'aider des fonctions contenues dans le fichier \codesmall{PythonSample/python/conversion.h}. -\item Il suffit de dclarer la fonction au sein de la macro \codesmall{BOOST\_PYTHON\_MODULE} dans le fichier \codesmall{PythonSample/python/definition.cpp}. -\end{enumerate} -\end{small} - -Il ne reste plus qu' tester la fonction nouvellement incluse depuis le programme \codes{PythonSample/test/test.py}. Le contenu de chaque fichier modifi lors de ces tapes est prsent par la figure~\ref{boost_python_sample_concert} page~\pageref{boost_python_sample_concert}. - -\begin{figure}[ht] -\indexexemples{\textit{Boost Python}}{} -\begin{center}\begin{tabular}{@{}lr@{}} -Fichier \codes{libSample/mafonction.h} & Fichier \codes{libSample/mafonction.cpp} \\ -\indexexemples{\textit{Boost Python}}{, mafonction.h} -\begin{minipage}{6.7cm} -\begin{verbatimx} -#ifndef LIB_MAFONCTION_H -#define LIB_MAFONCTION_H - -#include - -void somme_vecteur ( - const std::vector &v1, - const std::vector &v2, - std::vector &res) ; - -#endif - - - - - - - - - -\end{verbatimx} -\end{minipage} -& \indexexemples{\textit{Boost Python}}{, mafonction.cpp} -\begin{minipage}{6.7cm} -\begin{verbatimx} -#include "mafonction.h" -void somme_vecteur ( - const std::vector &v1, - const std::vector &v2, - std::vector &res) -{ - if (v1.size () != v2.size ()) - throw std::runtime_error ( - "dimensions diffrentes") ; - res.resize (v1.size ()) ; - std::vector:: - const_iterator it1,it2 ; - std::vector::iterator it3 ; - for (it1 = v1.begin (), - it2 = v2.begin (), - it3 = res.begin () ; - it1 != v1.end () ; - ++it1, ++it2, ++it3) - *it3 = *it1 + *it2 ; -} -\end{verbatimx} -\end{minipage} -\\ -Fichier \codes{PythonSample/mafonction.h} & Fichier \codes{PythonSample/mafonction.cpp} \\ -\indexexemples{\textit{Boost Python}}{, mafonction.h} -\begin{minipage}{6.7cm} -\begin{verbatimx} -#ifndef PYTHON_MAFONCTION_H -#define PYTHON_MAFONCTION_H - -#include "python/definition.h" - -boost::python::list - python_somme_vecteur ( - boost::python::list v1, - boost::python::list v2) ; - -#endif - - - - - - - -\end{verbatimx} -\end{minipage} -& -\indexexemples{\textit{Boost Python}}{, mafonction.cpp} -\begin{minipage}{6.7cm} -\begin{verbatimx} -#include "python/definition.h" -#include "mafonction.h" -#include "../libsample/mafonction.h" -#include "python/conversion.h" -#include "python/conversion.hpp" -boost::python::list - python_somme_vecteur ( - boost::python::list v1, - boost::python::list v2) -{ - std::vector cv1,cv2,cres ; - PythonConvert (v1, cv1) ; - PythonConvert (v2, cv2) ; - somme_vecteur (cv1, cv2, cres) ; - boost::python::list res ; - PythonConvert (cres, res) ; - return res ; -} -\end{verbatimx} -\end{minipage} -\\ -Fichier \codes{PythonSample/python/main.cpp} & Fichier \codes{PythonSample/test/test.py} \\ -\indexexemples{\textit{Boost Python}}{, main.cpp} -\begin{minipage}{6.7cm} -\begin{verbatimx} -// ... -#include "../mafonction.h" -BOOST_PYTHON_MODULE(PythonSample) -{ - // ... - def ("somme_vecteur", - &python_somme_vecteur, - (boost::python::arg ("v1"), - boost::python::arg ("v2")), - "retourne la somme de deux vecteurs"); - // ... -} ; -\end{verbatimx} -\end{minipage} -& -\indexexemples{\textit{Boost Python}}{, test.py} -\begin{minipage}{6.7cm} -\begin{verbatimx} -import PythonSample as PS -v1 = [1.0, 2.0] -v2 = [6.5, 7.8] -v3 = PS.somme_vecteur (v1, v2) - - - - - - - - -\end{verbatimx} -\end{minipage} - -\end{tabular}\end{center} -\caption{Six fichiers modifis pour ajouter une fonction dans un module \pythons crit en \textit{C++} partir de l'exemple -accessible depuis l'adresse \httpstyle{http://www.xavierdupre.fr/}.} -\label{boost_python_sample_concert} -\end{figure} - - - - - - - - -\subsection{Garbage collector et pointeur} - -Le langage \pythons gre lui-mme la destruction des objets au travers d'un \emph{garbage collector}.\indexfr{garbage collector} Cela signifie qu'un objet cr en \pythons provenant d'un module dfini dans module en~\textit{C++} sera lui aussi dtruit par \python. A partir du moment o le destructeur d'un objet libre les pointeurs qu'il a allou, la mmoire ne sera pas corrompue. Ce schma ne permet pas de prvoir quand l'objet sera dtruit. - -Pour parer aux problmes ventuels qui pourraient survenir notamment lorsqu'un objet contient des pointeurs sur des donnes dtenues par un autre objet, il est possible de spcifier \textit{Boost Python}\indexfr{pointeur} qu'un rsultat est une rfrence~: son identificateur \pythons peut tre dtruit mais pas l'objet qu'il dsigne. C'est l'objet du template \codes{boost::python::return\_internal\_reference<>()}. \indexboost{return\_internal\_reference} Il est utilis pour spcifier qu'une fonction retourne un rsultat qui ne doit pas tre dtruit. - -Par exemple, on utilise cette fonctionnalit pour dfinir un oprateur d'affectation comme l'oprateur~\texttt{+=}. La fonction suivante a la mme signature \textit{C++} que l'oprateur~\texttt{+=}. -\vspaceneg -\begin{verbatimx} -class PythonClassSample -{ - ... - PythonClassSample & __iadd__ (const PythonClassSample &a) ; - ... -} ; -\end{verbatimx} -\vspaceneg -Son rsultat est une rfrence sur un objet existant. Si aucune mention spcifique n'est prcise lors de l'export de la mthode (avec \codes{def}), lors d'un appel l'oprateur~\texttt{+=}, \pythons va considrer que le rsultat est un objet diffrent alors qu'il s'agit de deux identificateurs \pythons faisant rfrence au mme objet~\textit{C++}. C'est pour cela qu'on ajoute l'argument suivant la mthode \codes{def}~: -\vspaceneg -\begin{verbatimx} - x.def ("__iadd__", - &PythonClassSample::__iadd__, - boost::python::return_internal_reference<>(), - "addition") ; -\end{verbatimx} -\vspaceneg -De cette faon, il y aura bien deux identificateurs \pythons faisant rfrence au mme objet~\textit{C++}. C'est aussi cette syntaxe qui permet de dclarer une fonction retournant un pointeur sur un objet~\textit{C++}. - - -\subsection{Utilisation, installation} - -Le module termin se compose de trois fichiers~: - -\begin{small} -\begin{enumerate} -\item la DLL compile avec le code C++ du module, -\item un fichier portant le mme nom que la DLL mais d'extension \codesmall{.py}~: \codesmall{PythonSample.py}, -\item un fichier \codesmall{\_\_init\_\_.py}\indexfr{\codesindex{\_\_init\_\_.py}}\indexmoduleund{\_\_init\_\_.py}. -\end{enumerate} -\end{small} - -Voici ce fichier pour l'exemple prsent au paragraphe~\ref{python_boost_exemple}. La fonction importante de ce fichier est \codes{load\_dynamic} qui charge la DLL en mmoire au cas o elle n'aurait jamais t charge.\indexfonction{load\_dynamic}\indexmoduleint{imp} -\vspaceneg -\inputcode{../python_cours/programme/PythonSample.py}{import d'une DLL} - - - - - -\subsection{Dtails sur l'exemple du paragraphe~\ref{python_boost_exemple}} -\indexfr{version, debug, release} -Certains fichiers exposs ici ont t simplifis par rapport l'exemple tlchargeable. Celui-ci a t configur de manire produire deux DLL, une autre pour la version \textit{release} \codes{PythonSample.dll} et une pour la version \textit{debug} \codes{PythonSampled.dll}. Ceci permet d'utiliser l'une ou l'autre des versions dans le mme programme. La version \textit{debug} facilite la correction des erreurs qui pourraient survenir lors de l'utilisation du module sous \python (voir le paragraphe~\ref{debuggage_cplusplus_boust_python}). Il suffit alors d'crire~: -\vspaceneg -\begin{verbatimx} -import PythonSampled as PythonSample -# au lieu de import PythonSample -\end{verbatimx} -\vspaceneg -De cette faon, passer d'une DLL l'autre est simple et permet de dbugger, tche qu'introduit le paragraphe suivant. Si le programme \pythons s'tale sur plusieurs fichiers, il est plus pratique d'ajouter au dbut de chacun fichier qui utilise le module~\textit{C++}~: -\vspaceneg -\begin{verbatimx} -import sys -if "PythonSampled" in sys.modules : PythonSample = sys.modules ["PythonSampled"] -else : import PythonSample -\end{verbatimx} - - - - -\subsection{Debuggage}\indexfr{dbugger}\label{debuggage_cplusplus_boust_python}\indexfr{version, debug, release} - -Il ne serait pas pensable de dvelopper des outils sans pouvoir utiliser un dbuggeur. Dans l'exemple prsent au paragraphe~\ref{python_boost_exemple}, le fichier \codes{testd.py} n'utilise pas le module compil dans sa version \textit{release} mais dans sa version \textbf{\textit{debug}}. L'excution est plus lente mais permet de faire appel au dbuggeur pour corriger une ventuelle erreur d'excution. \indexfr{dbugger}\indexfr{version, debug, release}\indexfr{debug} - -Une manire de dbugger consiste momentanment arrter l'excution du programme \pythons ( l'aide de la fonction \codes{raw\_input}\indexfonction{raw\_input} par exemple), le temps d'attacher le dbuggeur de \textit{Microsoft Visual~C++} au processus dont le nom est \textit{python.exe} ou \textit{pythonw.exe}. Il ne reste plus qu' placer des pointeurs d'arrt\indexfr{pointeur d'arrt} puis continuer l'excution du programme \pythons jusqu' ce que ces pointeurs d'arrt soient atteints.\indexfr{pointeur d'arrt} - -Une seconde mthode consiste volontairement insrer dans le code~\textit{C++} du module l'instruction \codes{\_\_debugbreak ()}. Lorsque le module est excut via un programme \pythons et qu'il arrive sur cette ligne, il vous demande l'autorisation de continuer l'excution via un dbuggeur. Il faudra penser enlever la ligne une fois le module corrig.\ifnotellipse{\indexfr{\codesindex{\_\_debugbreak}}}\indexboost{\_\_debugbreak} - -Il reste toutefois une dernire faon plus classique de dbugger qui est l'ajout dans le code d'instructions crivant des messages dans un fichier texte. On crit des \textit{logs} ou des \textit{traces}.\indexfr{logs}\ifnotellipse{\indexfr{traces}} De cette faon, lorsque le programme provoque une erreur, on connat la squence de messages gnrs par le programme. S'ils sont suffisamment explicites, cela permet de corriger l'erreur. Sinon, l'ajout de messages supplmentaires puis une nouvelle excution du programme permettront d'tre plus prcis quant la cause de l'erreur. - -Outre ces trois mthodes de dbuggage, il est possible qu'un module doivent retourner un code d'erreur ou gnrer une exception\indexfr{exception} qui soit attrape par l'interprteur \pythons puis afficher. C'est l'objet des lignes qui suivent~: -\vspaceneg -\begin{verbatimx} -if () - throw std::runtime_error ("message d'erreur") ; -\end{verbatimx} -\vspaceneg -Toute exception drivant de \codes{runtime\_error} sera intercepte par l'interprteur \python. La librairie \textit{Boost Python} gnre galement des exceptions notamment lorsque les paramtres envoys une fonction du module ne correspondent pas avec sa signature. - -En terme d'architecture, \indexfr{architecture} il est conseill de bien scinder la partie utilisant \textit{Boost Python} des algorithmes. \textit{Boost Python} n'est qu'une passerelle vers \python. Il pourrait tre ncessaire de construire une autre passerelle vers d'autres langages tel que le \textit{Visual Basic pour Applications (VBA)}.\indexlangage{VBA} De mme, outre la passerelle vers \python, il est utile de construire un programme excutable permettant de tester les algorithmes crits en~\textit{C++} avant de les exporter. Cela rduit beaucoup le temps de dbuggage qui peut alors grer sparment la partie \textit{C++} de la partie interfaage entre \pythons et \textit{C++}. - - -%------------------------------------------------------------------------------------------ - -\subsection{Pour aller plus loin}\label{boost_python_aller_plus_loin} - -La librairie \textit{Boost Python}\footnote{\httpstyle{http://www.boost.org/libs/python/doc/}} permet de faire beaucoup plus de choses que ce qui est prsent dans ces paragraphes. Ceux-ci contiennent nanmoins l'essentiel pour exporter vers \pythons les objets les plus simples. Il est galement possible de~: - -\begin{small} -\begin{itemize} -\item surcharger une mthode~\textit{C++} dans un programme \python, -\item excuter un programme crit en \pythons depuis un programme~\textit{C++}. -\end{itemize} -\end{small} - - -Il faut parfois une certaine dose de volont et de tnacit pour parvenir matriser un outil tel que \textit{Boost Python}, surtout lorsqu'une erreur se dclare dans le code de librairie aprs une modification en dehors de cette mme librairie. - - - - -\firstpassagedo{ - \begin{thebibliography}{99} - \input{python_cours_biblio.tex} - \end{thebibliography} -} - - - -\input{../../common/livre_table_end.tex}% -\input{../../common/livre_end.tex}% \ No newline at end of file diff --git a/_todo/chapn_tools.tex b/_todo/chapn_tools.tex deleted file mode 100644 index eb02ce13..00000000 --- a/_todo/chapn_tools.tex +++ /dev/null @@ -1,2174 +0,0 @@ -\input{../../common/livre_begin.tex}% -\firstpassagedo{\input{python_cours_titre.tex}} -\input{../../common/livre_table_begin.tex}% -%\firstpassagedo{\input{python_cours_chapter.tex}} - - - - - - - - -%------------------------------------------------------------------------------------------------------------- -\chapter{Outils d'aide au dveloppement} -\label{chap_tools} -%------------------------------------------------------------------------------------------------------------- - - -Ce chapitre prsente diffrents outils qui accompagnent la cration d'une application dans quelque langage de programmation que ce soit. Les premiers outils prsents sont des modules du langage \pythons qui permettent de fiabiliser un programme malgr de nombreuses modifications ou de mesurer le temps pass dans chaque fonction. - -Les autres outils sont des applications facilitant le dveloppement etle partage d'information. Le premier, \emph{Tortoise SVN}, est un logiciel de suivi de version~: il permet de conserver l'historique de vos modifications. Le second, \emph{HTML Help Workshop}, permet de construire des fichiers d'aide au format \emph{chm}. Le troisime, \emph{InnoSetup}, permet de construire un installateur, un programme qui installera votre application sur une autre machine. Le dernier outil, \emph{MoinMoin} est ce qu'on appelle un \textit{Wiki}, il permet facilement de partager l'information au sein d'une entreprise en offrant chacun la possibilit de modifier des pages internet et d'y effectuer des recherches.\indexoutil{Wiki} - -\begin{xremark}{instructions d'installation et de configuration} -Les instructions qui permettent d'installer et de configurer les applications \textit{Apache}, \textit{SVN}, \textit{MoinMoin}, ... sont extraites des sites internet de chaque applications. Elles sont valides pour les numros de version cits dans ce document mais il est possible qu'elles voluent dans le futur. Pour des versions plus rcentes, il est probable que ces installations se modifient\footnote{Les versions testes lors de l'criture de ce document sont \textit{Apache 2.2.8}, \textit{SVN 1.4.6}, \textit{MoinMoin 1.6.3}, \textit{InnoSetup 5.2.3}, \textit{Tortoise SVN 1.4.8}, \textit{HTML Help Workshop 4.74}, \textit{MySQL 5.0.51}.} . -\end{xremark} - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{Modules d'aide au dveloppement} - -L'intrt de la programmation rside rarement dans le programme construit mais plutt dans ce qu'il permet de faire. Les outils qui suivent permettent de gagner du temps pas forcment lors de la conception mais plutt lors de la finalisation d'une application\footnote{Certains site comme celui-ci \httpstyle{http://sebsauvage.net/python/snyppets/index.html} sont plus utiles lors de la conception, ils recensent de nombreux usages du langages toujours illustrs d'un exemple.} - - - -\subsection{Temps d'excution} \indexfrr{temps}{excution}\indexfrr{temps}{mesure} - -Le cot d'un algorithme dfinit sa complexit en fonction de la taille des donnes qu'il manipule mais cette information est rarement disponible. Lorsqu'un programme est trop long, avant de pouvoir le modifier, il faut savoir quels sont les lments consommateurs de temps, c'est ce que permettent de faire les modules \codes{profile} et \codes{pstats}.\indexmoduleint{profile}\indexmoduleint{pstats} Le code suivant a t ajout au programme \codes{genchm.py} dfinit au paragraphe~\ref{section_chm_programme}, page~\pageref{section_chm_programme}. -\indexexemples{gnration automatique de l'aide}{} -\begin{verbatimx} -def run () : - files = [".\\genchm.py", ".\\genhelp.py", "os", "sys"] - res = genhelp.genhelp (files) - print res # ['genchm.html', 'genhelp.html', 'os.html', 'sys.html'] - genchm (res, "GenHelp") - -if __name__ == "__main__" : - # crit des informations relatives l'excution de la fonction - # run () dans le fichier profile.txt - import profile - profile.run ('run()', "profile.txt") - - # rcupre les informations stockes dans profile.txt - # et construit le nombre de passages dans chaque - # fonction et les temps d'excution moyen - import pstats - p = pstats.Stats('profile.txt') - p.strip_dirs().sort_stats(-1).print_stats() -\end{verbatimx} -Le rsultat est le suivant~: -\begin{verbatimx} -Mon May 12 22:38:02 2008 profile.txt - - 77 function calls in 5.557 CPU seconds - - Ordered by: standard name - - ncalls tottime percall cumtime percall filename:lineno(function) - 5 0.000 0.000 0.000 0.000 :0(append) - 4 0.000 0.000 0.000 0.000 :0(close) - 2 0.000 0.000 0.000 0.000 :0(len) - 4 0.003 0.001 0.003 0.001 :0(open) - 16 0.000 0.000 0.000 0.000 :0(replace) - 1 0.001 0.001 0.001 0.001 :0(setprofile) - 2 0.000 0.000 0.000 0.000 :0(split) - 5 5.551 1.110 5.551 1.110 :0(system) - 4 0.000 0.000 0.000 0.000 :0(write) - 1 0.000 0.000 5.556 5.556 :1() - 1 0.000 0.000 2.562 2.562 genchm.py:102(genchm) - 1 0.000 0.000 0.001 0.001 genchm.py:11(genhhp) - 1 0.000 0.000 5.556 5.556 genchm.py:113(run) - 1 0.000 0.000 0.001 0.001 genchm.py:42(gen_premierepage) - 13 0.000 0.000 0.000 0.000 genchm.py:54(genhh_input) - 1 0.000 0.000 0.001 0.001 genchm.py:61(genhhc) - 8 0.000 0.000 0.000 0.000 genchm.py:7(g) - 1 0.000 0.000 0.001 0.001 genchm.py:83(genhhk) - 4 0.000 0.000 2.993 0.748 genhelp.py:17(generate_help_file) - 1 0.000 0.000 2.994 2.994 genhelp.py:26(genhelp) - 0 0.000 0.000 profile:0(profiler) - 1 0.000 0.000 5.557 5.557 profile:0(run()) -\end{verbatimx} -Ces informations nous rvle que la fonction la plus souvent appele \codes{replace} ne consomme presque pas de temps d'excution. La fonction \codes{generate\_help\_file} dure prs de trois quarts de seconde chaque appel. La fonction \codes{run} est la plus longue car elle cumule le temps pass dans toutes les autres. - - -\subsection{Tests systmatiques avec \codes{doctest}} \indexfrr{test}{systmatique} - -Lorsqu'il s'agit d'un programme court, il n'est pas ncessaire de bien rflchir la structure d'un programme ni vrifier de temps en temps que ce qu'on a crit auparavant continue de fonctionner malgr toutes les modifications apportes au programme. Car il existe certains piges rcurrents en informatique inhrents toutes les applications consquentes. Le schma suivant retrace l'historique de la cration de trois fonctions. -\begin{center}\begin{tabular}{lll} -\codes{fonction\;A} & crite en janvier & \\ \hline -\codes{fonction\;B} & crite en janvier & utilise \codes{fonction\;A} \\ \hline -\codes{fonction\;C} & crite en juin & utilise \codes{fonction\;A} -\end{tabular}\end{center} -En juillet, on s'aperoit qu'il faut modifier \codes{fonction\;C}, cette modification implique la modification de \codes{fonction\;A}. Quel est l'impact sur \codes{fonction\;B} qui est une vieille fonction mais dont le comportement ne doit absolument pas changer~? Ce cas de figure se produit frquemment lors de la conception d'une application et il n'est pas toujours facile de prvoir les consquences d'une modifications d'une fonction lorsque celle-ci est appele d'un peu partout dans le code. - -Une des solutions proposes par le langage \python est le module \codes{doctest}.\indexmoduleint{doctest} Il permet de simplifier le travail de vrification pour des fonctions qui retourne un rsultat. Plus prcisment, il est possible de spcifier une liste d'appels une fonction et de comparer le rsultat avec un rsultat attendu ou souhait. - -L'exemple suivant utilise une fonction d'addition de deux listes. Elle retourne une liste de mme taille contenant la somme membre membre des deux listes. On souhaite vrifier que cette fonction retourne les bonnes valeurs pour certaines valeurs d'entres connues. Dans ce cas, on souhaite s'assurer que la fonction retourne bien~: -\begin{center}\begin{tabular}{|l|l|l|} \hline -\codes{l1} & \codes{l2} & rsultat \\ \hline -\codes{[]} & \codes{[]} & \codes{[]} \\ -\codes{[1,2]} & \codes{[3,-1]} & \codes{[4, 1]} \\ \hline -\end{tabular}\end{center} - -La premire tape est d'ajouter ces rsultats dans le commentaire associ la fonction. On fait prcder l'appel de \codes{>>>} et on crit le rsultat sur la ligne suivante. - -\begin{verbatimx} ->>> addition ( [1,2], [3,-1]) -[4, 1] -\end{verbatimx} - -Il suffit ensuite d'ajouter une fonction appelant ces tests pour le module en question~: -\indexexemples{\codesindex{doctest}}{} -\begin{verbatimx} -def _test(): - import doctest - print doctest.testmod() -\end{verbatimx} -Si le test est valid, il ne se passe rien lorsqu'on appelle la fonction \codes{\_test}, sinon le message suivant apparat~: -\begin{verbatimx} -File "testdoc1.py", line 6, in __main__.addition -Failed example: - addition ( [1,2], [3,-1]) -Expected: - [4, 1] -Got: - [4, 1] -********************************************************************** -1 items had failures: - 1 of 2 in __main__.addition -***Test Failed*** 1 failures. -\end{verbatimx} -Dans ce cas prcis, une erreur se dclenche car un espace de trop a t ajout au rsultat attendu. Il suffit d'appeler rgulirement ou chaque modification du programme la fonction \codes{_test} de tous les modules d'un programme pour s'assurer que les rsultats sont toujours ceux attendus. On peut mettre plusieurs tests bout bout, le programme complet donne~: - -\inputcode{../python_cours/programme/testdoc1.py}{exemple de test avec \codesindex{doctest}} - -Il reste grer le cas o la fonction retourne une exception. Il suffit d'inclure le texte suivant dans le commentaires\footnote{Il faut faire attention aux espaces rsiduels en fin de ligne, ceux-ci doivent tre supprims dans le commentaires}. Les deux premires lignes sont identiques chaque fois, la dernire est l'exception lance par la fonction. -\begin{verbatimx} - Traceback (most recent call last): - ... - Exception: listes de tailles diffrentes -\end{verbatimx} - -Le programme complet suit~: - -\inputcode{../python_cours/programme/testdoc2.py}{exemple de test plus complet avec \codesindex{doctest}} - -Le module \codes{doctest} reste cependant trs limit puisqu'il ne permet que de tester le rsultat d'une fonction et non un paramtre modifi comme une liste. C'est une manire de faire simple et vite pour des fonctions courtes et retournant des rsultats principalement numriques. Ce module permet nanmoins d'introduire le concept de tests automatiques d'une application ou tests unitaires dvelopps par le paragraphe suivant. - - -\subsection{Tests unitaires avec \codes{unittest}} \indexfrr{test}{unitaire} \indexmoduleint{unittest} - -Les tests unitaires sont avant tout un concept, ils permettent de fiabiliser une application en rptant les mmes tests chaque modification du programme et chaque fois qu'une application doit tre transmise aux utilisateurs finaux\footnote{C'est ce qu'on appelle une mise en production.\indexfr{mise en production}} Le module \codes{unittest} facilite la mise en place de ces tests mais ils pourraient tout--fait tre implments sans l'utiliser. - -L'objectif reste identique celui vis par le module \codes{doctest}, il est simplement plus ambitieux. Cette fois-ci, le code correspondant aux tests sera spar du code de l'application elle-mme. Les tests inclus dont de deux types~: -\begin{enumerate} -\item vrifier que la fonction fait bien ce pour quoi elle a t cr y compris dans les cas limites, on vrifiera par exemple qu'une fonction de tri retourne bien un tableau tri, qu'une fonction retourne bien le bon code d'erreur dans un cas prcis -\item vrifier que la correction apporte suite la dcouverte d'un bug continue bien de corriger ce bug -\end{enumerate} - -Ce paragraphe n'abordera pas en dtail toutes les possibilits du module \codes{unittest}, ils ne sont pas indispensables au travail d'un ingnieur moins que son travail n'volue vers la cration d'une application qui dpasse son propre usage ou d'une application destine durer. Le programme dont on souhaite vrifier la fiabilit est celui du paragraphe prcdent~: - -\inputcode{../python_cours/programme/testunit1.py}{module tester} - -On crit maintenant un autre fichier contenant les trois tests implments avec le module \codes{doctest}. Deux concernaient des rsultats retourns par la fonction \codes{addition} et le dernier un cas gnrant une exception. Pour dfinir un test, le principe est le suivant~: -\begin{enumerate} -\item crer une classe hritant de \codes{unittest.TestCase} -\item ajouter une mthode dont le nom commence par \codes{test} -\item dans le corps de cette mthode, crire le code du test, ce dernier est valid si une srie de conditions est vrifie, pour chaque condition, on ajoutera l'instruction \codes{assert \; condition} -\end{enumerate} -\indexkeyword{assert} -Le test est pass avec succs si les conditions prcdes du mot-cl \codes{assert} sont vraies. Si l'une d'elle est fausse, le test a chou et signifie que le programme est bugg. Pour lancer les tests, il faut appeler la fonction \codes{unittest.main ()}. Cela donne le programme suivant~: - -\inputcode{../python_cours/programme/testunit2.py}{liste de tests avec \codesindex{unittest}} - -Aprs avoir modifie la fonction \codes{addition} de faon faire chouer le second test \codes{test\_addition}, le message retourn par \pythons est~: -\begin{verbatimx} -====================================================================== -ERROR: test_addition : test de [1,2] + [3,-1] != [4,1] ----------------------------------------------------------------------- -Traceback (most recent call last): - File "testunit2.py", line 16, in test_addition - assert l [0] == 4 and l [1] == 1 -IndexError: list index out of range -\end{verbatimx} -Les premires lignes reprennent le commentaires associes la mthode de test. Les lignes suivantes permettent de comprendre o l'erreur est apparue et quelle condition a fait chouer le test. La fonction \codes{addition} a galment t intentionnellement modifie pour ne pas gnrer d'exception lorsque les tailles de listes sont diffrentes. Le message suivant apparat~: -\begin{verbatimx} -====================================================================== -FAIL: on vrifie que l'addition de deux listes de tailles diffrentes gnre une exception ----------------------------------------------------------------------- -Traceback (most recent call last): - File "testunit2.py", line 27, in test_exception - assert str (e.__class__ .__name__) != "AssertionError" -AssertionError -\end{verbatimx} -Le module \codes{unittest} indique galement le temps pass effectuer ces tests et le nombre de tests lancs. Lorsqu'il existe une multitude de tests, il est sans doute prfrable de les rpartir sur plusieurs fichiers la fois. Il faut pouvoir les lancer depuis un seul fichier qui passera tous les tests unitaires en sries. C'est l'objectif du programme suivant qui rcupre tous les fichiers \codes{test_*.py} du rpertoire, les importe puis cre des suites de tests unitaires pour les mthodes \codes{test...} des classes intitules \codes{Test...}. -% -\inputcode{../python_cours/programme/alltest.py}{excution de tests unitaires rpartis sur plusieurs fichiers} - - - -\subsection{Ecrire des fichiers de log} \indexfr{logs} - -module \codes{logging} \indexmoduleint{logging} - - - -\subsection{Lancer un programme \pythons en ligne de commande} \indexfr{ligne de commande}\indexfr{commande} - -Certains dveloppements ncessitent de pouvoir excuter un programme \pythons en ligne de commande sans intervention extrieure. Ce peut tre un programme de synchronisation de deux rpertoires ou la rcupration du contenu de pages HTML, des tches souvent excutes la nuit une heure o personne n'est prsent pour le faire. Prenons par exemple le cas d'un programme trs simple de synchronisation qui recopie tous les fichiers d'un rpertoire vers un autre. La fonctionne \codes{copie\_repertoire} effectue cette tche. \indexmoduleint{glob}\indexmoduleint{shutil} -\begin{verbatimx} -# coding: cp1252 -import glob -import shutil -def copie_repertoire (rep1, rep2) : - """copie tous les fichiers d'un rpertoire rep1 vers un autre rep2""" - li = glob.glob (rep1 + "/*.*") - for l in li : - to = l.replace (rep1, rep2) # nom du fichier copi (on remplace rep1 par rep2) - shutil.copy (l, to) -copie_repertoire ("c:/original", "c:/backup") -\end{verbatimx} -% -Cette tche est en plus excut sur deux rpertoires et on ne voudrait pas avoir deux programmes diffrents alors que la tche est la mme. On souhaite pouvoir lancer le programme \pythons et lui spcifier les deux rpertoires, c'est--dire tre capable de lancer le programme comme suit (voir galement figure~\ref{poyton__cmd_synchor})~: -\begin{verbatimx} -c:\python25\python.exe synchro.py c:/original c:/backup -\end{verbatimx} - - \begin{figure}[ht] - \figureoneimageusual{ \caption{Un programme \pythons lanc en ligne de commande.} } - { \includegraphics[width=13cm]{\filextellipse{../python_cours/image/cmds}{../python_cours/image/cmds}} } - { \label{poyton__cmd_synchor}} - \end{figure} - -\indexmoduleint{sys} -Pour lancer un programme \pythons en ligne de commande, il faut crire dans une fentre de commande ou un programme d'extension \textit{bat}\indexfrr{extension}{bat} les instructions suivantes spares par des espaces~: -\begin{verbatimx} -interprteur_python programme_python argument1 argument2 ... -\end{verbatimx} -% -Il faut maintenant rcuprer ces paramtres au sein du programme \pythons grce au module \codes{sys} qui contient une variable \codes{argv} contenant la liste des paramtres de la ligne de commande. S'il y a deux paramtres, cette liste \codes{argv} contiendra trois lments~: -\begin{enumerate} -\item nom du programme -\item paramtre 1 -\item paramtre 2 -\end{enumerate} -% -Le programme suivante utilise ce mcanisme avec le programme \codes{synchro} contenant la fonction \codes{copie\_repertoire}~: -% -\inputcode{../python_cours/programme/synchro.py}{lancer un programme \pythons en ligne de commande} -% - -\begin{xremark}{paramtres contenant des espaces} -Lorsque les paramtres crits sur la ligne de commande contiennent eux-mmes des espaces, il faut les entourer avec des guillemets. -\begin{verbatimx} -c:\python25\python.exe c:\batch\synchro.py "c:\Program Files\source" "c:\Program Files\backup" -\end{verbatimx} -\end{xremark} - -Pour des besoins plus complexes, le module \codes{getopt} propose des fonctions plus labores pour traiter les paramtres de la ligne de commande.\indexmoduleint{getopt} - -\subsection{Lancer un programme \pythons en ligne de commande depuis un programme \python} \indexfr{ligne de commande}\indexfr{commande} - -Il est parfois utile de lancer un programme excutable en ligne de commande depuis un programme \python. C'est assez pratique pour ouvrir automatiquement un diteur de texte ou lancer un navigateur affichant directement une page internet prcise. Il existe plusieurs faons de faire cela. La premire est l'utilisation de la fonction \codes{system}\indexfonction{system} du module \codes{os}.\indexmoduleint{os} L'exemple suivant ouvre automatiquement l'diteur de texte \textit{SciTe}\indexoutil{SciTe} sur le fichier \codes{fichier.txt}. -\indexexemples{ligne de commande \textit{SciTe}}{} -\begin{verbatimx} -os.system ("scite -open:fichier.txt") -\end{verbatimx} -% -Un autre moyen est l'utilisation du module \codes{subprocess}.\indexmoduleint{subprocess} Il permet d'attendre ou non la fin de l'excution de la ligne de commande. -\indexexemples{\codesindex{subprocess}}{} -\begin{verbatimx} -import subprocess -args = ["scite.exe", "-open:fichier.txt"] -proc = subprocess.Popen(args) -retcode = proc.wait() # on attend la fin de l'excution -if retcode!=0: - # ici, traiter les erreurs -\end{verbatimx} -% -Certains programmes en ligne de commande crivent des informations dans la fentre d'excution. C'est le cas par exemple d'une instruction \codes{print} dans un programme \python. lorsqu'on excute un programme en ligne de commande, ces informations sont perdues moins de les rcupres. La premire solution consiste ajouter \codes{>>output.txt} en fin de ligne de commande de sorte que ces informations seront stockes dans le fichier \codes{output.txt}. -\indexexemples{\codesindex{subprocess}}{} -\begin{verbatimx} -import subprocess -args = ["scite.exe", "-open:fichier.txt", ">>output.txt"] -proc = subprocess.Popen(args) -\end{verbatimx} -% -La seconde option consiste rediriger la sortie vers le programme appelant toujours avec la fonction \codes{Popen}.\indexfonction{Popen} -% - -( venir) - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - - -\section{Tortoise SVN : suivi de version} \indexoutil{Tortoise SVN} - -Le premier des outils est sans doute installer avant de commencer programmer. \emph{Tortoise SVN}\footnote{\httpstyle{http://tortoisesvn.tigris.org/}}\footnote{\textit{Tortoise SVN} comprend en fait deux composants, le premier \textit{SVN} est le logiciel proprement dit, il existe sur tout type de plateforme. \textit{Tortoise} est l'interface graphique qui permet d'utiliser \textit{SVN} plus simplement mais elle est spcifique \textit{Windows}.} permet de conserver l'historique des modifications d'un fichier, d'une arborescence de fichiers. Le logiciel peut grer tout type de fichiers, toutefois, il est particulier indiqu pour les fichiers textes. C'est un outil galement qui facilite grandement le travail plusieurs sur les mmes fichiers. - -Le principe est d'avoir un rpertoire o sont stockes l'ensemble des fichiers et toutes les modifications qui y ont t apportes. Ce rpertoire principal porte souvent le nom de \emph{repository} (voir figure~\ref{fig_svn_1}).\indexfr{repository} Cette copie principale n'est pas modifiable directement. Il faut en faire autant de copies qu'il y a d'intervenants sur le projet. - - \begin{figure}[ht] - \figureoneimage { \caption{SVN conserve une copie principale que personne ne peut modifier directement. - On peut en fait autant de copies - qu'il y a de programmeurs. Chacun d'entre eux peut modifier sa copie sans interfrer sur celle des autres. } } - { \includegraphics[height=2.5cm, width=7cm]{\filextel{../python_cours/image/svn1}} } - { \label{fig_svn_1}} - \end{figure} - -\subsection{Utilisation personnelle} - -Cet outil est galement utile pour ses propres fichiers, pour conserver l'historique des modifications apportes un ensemble de fichiers. La premire tape est l'installation. - -\subsubsection{Installation et cration d'un repository} \label{troitoise_installation} \indexoutilz{TortoiseSVN}{installation} - -L'installation commence par l'excution d'un installateur \textit{Windows}\footnote{L'installation usage personnel est simple, l'utilisation pour un usage multiple permet une utilisation personnelle mais ncessite des tapes de configurations plus importantes et l'installation de trois logiciels (voir paragraphe~\ref{svn_installation_multiple}).}. Celle-ci ne pose pas de problme particulier. Une fois celle-ci termine, de nouveaux menus apparaissent dans l'explorateur \textit{Windows} lorsqu'on clique sur le bouton droit de la souris sur un rpertoire (voir figure~\ref{fig_svn_2ex}). La cration d'un repository consiste tout d'abord crer un rpertoire que SVN utilisera comme rpertoire principal. C'est un rpertoire que seul \textit{SVN} modifiera, le modifier soi-mme n'est pas conseill mme si certains fichiers de configuration peuvent l'tre mais cela sort du cadre de ce livre.\indexoutilz{SVN}{repository} - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[height=5cm, width=6cm]{\filextel{../python_cours/image/svn2ex}} & - \includegraphics[height=3cm, width=5cm]{\filextel{../python_cours/image/svn3r}} - \\ \hline - \end{tabular}\end{center} - \caption{ Aprs l'installation de SVN, de nouveaux menus apparaissent lors d'un clic droit de la souris au-dessus - d'un rpertoire. La seconde image intervient lorsqu'on cherche construire un repository, \textit{SVN} demande - quel type d'archivage il doit choisir. Il est prfrable de choisir le premier.} - \label{fig_svn_2ex} - \end{figure} - -L'tape suivante consiste crer un rpertoire dans le repository. Il faut encore cliquer sur le clic droit de la souris l'endroit o a t cr le repository et choisir \textit{RepoBrowser}. Ensuite, un nouveau clic droit de la souris dans la fentre qui s'ouvre permet de crer un nouveau rpertoire (choisir \textit{Add Folder}). Ce premier rpertoire porte souvent le nom de \textit{racine} ou \textit{root} ou encore \textit{trunk}.\indexoutilz{SVN}{cration d'un rpertoire} - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[width=3.4cm]{\filextel{../python_cours/image/svn5f}} & - \includegraphics[width=9cm]{\filextel{../python_cours/image/svn4f}} - \\ \hline - \end{tabular}\end{center} - \caption{ Cration du premier rpertoire du repository. } - \label{fig_svn_3f} - \end{figure} - -\subsubsection{Utilisation} - -Le principe de \textit{SVN} est de faire correspondre un rpertoire du disque dur au premier rpertoire du repository. Ce sera le rpertoire de travail. Le nom de l'opration est \textit{CheckOut} (voir figure~\ref{fig_svn_4s}).\indexoutilz{SVN}{CheckOut} \textit{SVN} cre un rpertoire si celui-ci n'existe pas et y insre galement un rpertoire cach \textit{.svn}.\indexoutilz{SVN}{.svn} Il contient des informations interne \textit{SVN}. Il ne faut ni le supprimer ni le modifier. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[width=3.4cm]{\filextel{../python_cours/image/svn61}} & - \includegraphics[width=10cm]{\filextel{../python_cours/image/svn72}} - \\ \hline - \end{tabular}\end{center} - \caption{ Cration d'une correspondance entre un rpertoire du disque dur et un rpertoire du repository. } - \label{fig_svn_4s} - \end{figure} - -Ajouter un fichier au rpertoire \textit{racine} du disque dur n'a pas d'effet sur le repository. Pour l'y inclure, il faut utiliser l'opration \textit{Commit} (voir la figure~\ref{fig_svn_5n}).\indexoutilz{SVN}{Commit} Il faut cocher la case associe au fichier cr, ajouter un commentaire et cliquer sur \textit{Ok}. - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[width=3cm]{\filextel{../python_cours/image/svn8nn}} & - \includegraphics[width=10.4cm]{\filextel{../python_cours/image/svn8n}} - \\ \hline - \end{tabular}\end{center} - \caption{ Ajout d'un fichier texte au repository.} - \label{fig_svn_5n} - \end{figure} - -Un icne vert apparat adoss au fichier cr (voir figure~\ref{fig_svn_6i}), il signifie que le fichier est identique dans le repository et dans le rpertoire associ. Sa modification entrane l'apparition d'un icne rouge qui signifie que la copie du disque dur a t modifie. La rptition de l'opration \textit{Commit} permet de basculer les modifications dans le repository et de faire apparatre l'icne vert. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[height=1cm, width=3cm]{\filextel{../python_cours/image/svn9a}} & - \includegraphics[height=1cm, width=3cm]{\filextel{../python_cours/image/svn9b}} - \\ \hline - \end{tabular}\end{center} - \caption{ Icnes \textit{SVN}.} - \label{fig_svn_6i} - \end{figure} - -Un nouveau clic droit sur le fichier modifi et la slection du sous-menu \textit{Log} permet d'afficher l'ensemble des modifications intervenues sur ce fichier (voir figure~\ref{fig_svn_7l}).\indexoutilz{SVN}{Log} Un double-clic sur le fichier en question permet de comparer deux versions conscutives, de voir les lignes ajoutes, supprimes et modifies. Cette fonctionnalit ne concerne que les fichiers textes. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[height=10cm, width=6cm]{\filextel{../python_cours/image/svn10a}} & - \includegraphics[height=7cm, width=11cm]{\filextel{../python_cours/image/svn10b}} - \\ \hline - \end{tabular}\end{center} - \caption{ Historique des modifications d'un fichier.} - \label{fig_svn_7l} - \end{figure} - -Les autres menus ne seront pas dtaills, leur exploration est laisse au soin du lecteur. Toutefois, l'un d'entre deux permet de rcuprer une vieille version d'un fichier, antrieure aux dernires modifications. De la mme manire, si un fichier est supprime par mgarde, celui-ci, jamais prsent dans le repository, peut tre rcupr tout moment. - - - -\subsubsection{Configuration} - -Un clic droit sur le rpertoire repository permet d'accder la partie \textit{Settings}.\indexoutilz{SVN}{Settings} Le seul paramtre dcrit dans ce paragraphe est celui intitul \textit{Global ignore patterns} de la section \textit{General} (voir figure~\ref{fig_svn_8s}). Il permet que certains fichiers ne soient pas pris en compte par \textit{SVN}. Par exemple, lorsqu'on programme en \python, de nombreux fichiers d'extension \textit{pyc} sont gnrs. Il ne sert rien de les conserver dans le repository puisque ceux-ci seront de toutes faons recrs par \pythons si ceux-ci ont t supprims ou si le fichier source leur origine a t modifi~: ce sont des fichiers temporaires. Pour viter que \textit{SVN} n'en tienne compte, il suffit d'ajouter l'expression \textit{*.pyc} dans le champ \textit{Global ignore patterns}. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[height=5cm, width=5cm]{\filextel{../python_cours/image/svn11a}} & - \includegraphics[height=7cm, width=11cm]{\filextel{../python_cours/image/svn11b}} - \\ \hline - \end{tabular}\end{center} - \caption{ Configuration de \textit{SVN}, il est possible de faire en sorte que \textit{SVN} ne tienne pas compte - de certains fichiers dans le champ \textit{Global ignore patterns}. S'il y a plusieurs filtres, - ils doivent tre spars par des espaces.} - \label{fig_svn_8s} - \end{figure} - -\subsubsection{Plusieurs copies du repository} - -Mme si ce n'est pas souvent utile, il est possible de travailler avec plusieurs copies du repository. Chaque copie doit tre construite avec la fonctionnalit \textit{CheckOut}. Une fois ces deux copies crs, il faut pouvoir propager les modifcations d'une copie l'autre. La fonctionnalit \textit{Commit} applique la copie modifie permet de transmettre des modifications au repository qui contient l'unique version officielle. Ensuite, la fonctionnalit \textit{Update}\indexoutilz{SVN}{Update} permet de mettre jour en chargeant depuis le repository les dernires modifications. Ce principe est illustr par le schma de la figure~\ref{fig_svn_sevcopie}. - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=3cm, width=10cm]{\filextel{../python_cours/image/svn12_}} - \\ \hline - \end{tabular}\end{center} - \caption{ Lorsqu'on travaille avec plusieurs copies, la fonctionnalit \textit{Update} fait les modifications depuis - le repository jusqu' une copie (celle sur laquelle on applique l'opration \textit{Update}. La fonctionnalit - \textit{Commit} est le chemin inverse~: on transmet les modifications depuis une copie vers le repository.} - \label{fig_svn_sevcopie} - \end{figure} - -Certains problmes peuvent survenir lorsqu'on travaille sur les mmes fichiers depuis les deux copies. Il faut toujours rappatrier les dernires modifications enregistres dans le repository~: un \textit{Commit} est toujours prcd d'un \textit{Update}. \textit{SVN} est capable dans la plupart des cas de grer les conflits. Seuls restent les cas o les mmes lignes du mme fichier sont modifies. Lors d'un \textit{Update}, on peut rcuprer une modification qui rentre en conflit sur la version en cours. Il faut alors rsoudre ce conflit puis indiquer \textit{SVN} que le conflit est rsolu (par l'intermdiaire des sous-menu accessibles avec la souris). \textit{SVN} n'autorisera pas de \textit{Commit} sur un fichier pour lequel il subsiste un conflit irrsolu.\indexoutilz{SVN}{Resolve} - - - -\subsection{Utilisation plusieurs} - -Une utilisation plusieurs requiert une machine accessible par tous sur laquelle sera install le repository. La communication entre cette machine et celles des autres utilisateurs se fera par l'intermdiaire d'un serveur. Le plus couramment utilis est le serveur \textit{Apache}. C'est une application qui va fonctionner en permanence sur l'ordinateur et qui permettra les changes d'informations. - -\subsubsection{Installation sur la machine contenant le repository} \label{svn_installation_multiple} - -\textbf{Installation de \textit{SVN}} \indexoutilz{SVN}{installation} - -L'installation est diffrente car l'application \textit{SVN} utilise est lgrement diffrente et il faut faire attention que \textit{SVN} et \textit{Apache} ont des numros de versions cohrents. On commence donc par l'installation de \textit{SVN}. Il faut tout d'abord tlcharger une version \textit{SVN} pour une version \textit{Apache} spcifique \footnote{Au moment o est crit ce livre, la version \textit{SVN} est 1.4.6 pour \textit{Apache 2.2}, \textit{SVN} est tlchargeable l'adresse \httpstyle{http://subversion.tigris.org/project\_packages.html} et apparat sous l'intitul \textit{Win32 packages built against Apache 2.2} pour \textit{Windows}.} - -Ensuite, on va crer un repository. Pour cela, il faut ouvrir une fentre de commande \textit{Windows} et crire les instructions suivantes pour crer un repository l'emplacement \codes{c:\backslash svnrepository}~: -\begin{verbatimx} -cd "rpertoire d'installation de SVN\bin" -svnadmin create c:\svnrepository -\end{verbatimx} - -\textbf{Installation de \textit{Apache}} -Voir paragraphe~\ref{apache_paragraphe_section} page~\pageref{apache_paragraphe_section}. - -\subsubsection{Installation sur les autres machines} - -L'installation est beaucoup plus simple puisqu'il suffit d'installer \textit{Tortoire SVN} (voir paragraphe~\ref{troitoise_installation}, page~\pageref{troitoise_installation}). Il suffira de faire une opration \codes{checkout} depuis le repository \httpstyle{http://localhost/svn/} \httpstyle{http://127.0.0.1/svn/} o \codes{127.0.0.1} est l'adresse~IP de la machine o est installe le repository. - -\begin{xremark}{connexion sur \textit{Apache} impossible depuis une autre machine du rseau} \label{remark_firewall} -Il est possible que l'accs la machine o est install \textit{Apache} soit impossible depuis une autre machine. Il y a deux causes possibles, la premire est que les deux machines ne peuvent pas communiquer ensemble. Pour vrifier cela, il suffit d'ouvrir une fentre de commande \textit{Windows} et d'crire depuis la machine distante~: -\indexexemples{\codesindex{ping}}{} -\begin{verbatimx} -ping 127.0.0.1 -\end{verbatimx} -On suppose que \codes{127.0.0.1} est l'adresse IP de la machine o figure \textit{Apache}. Si le rsultat est ngatif, il faut d'abord rsoudre ce problme l. La seconde cause est le \textit{firewall}\indexfr{firewall} (ou \textit{pare-feu})\indexfr{pare-feu} qui empche les connexions entrantes. Il est possible que ce soit le \textit{firewall} de \textit{Windows} qui soit utilis, il est possible de le dsactiver depuis le panneau de contrle ou le laisser activer mais autoriser une exception concernant le port qu'coute le serveur \textit{Apache}. -\end{xremark} - -\begin{xremark}{\textit{Apache} coute un autre port que le port 80}\label{remark_port_81} -Au cas o \textit{Apache} coute un autre port que le port 80, il faut le prciser lorsqu'on se connecte depuis une machine distante. Si le port cout est le port~81, il faudra crire dans la barre d'adresse~: -\begin{verbatimx} -http://127.0.0.1:81/ -\end{verbatimx} -\end{xremark} - -\subsubsection{Backup} \indexfr{backup}\indexoutilz{SVN}{backup} - -Il peut tre intressant de sauvergarder rgulirement le repository au cas o la machine qui le contiendrait tombe en panne. Cette option ne sera pas dtaille ici mais elle est disponible avec \codes{Apache} qui autorise l'excution de tches intervalles rguliers. - -\subsubsection{Via internet} - -\textit{SVN} est plus souvent install pour tre utilis l'intrieur d'une entreprise et n'est accessible que depuis son rseau local. Nanmoins, il n'est pas exclu de travailler depuis des postes distants via Internet. Comme pour une utilisation interne, cela suppose qu'un ordinateur servira de repository, la diffrence viendra de l'URL permettant de se connecter au seveur \textit{SVN} qui pointera vers l'extrieur. Toutefois, cette configuration soulve des problmes de scurit. Il faut que le serveur soit bien configur pour ne laisser l'accs aux fichiers partags qu' ceux qui y sont autoriss. - -\subsubsection{Limitations} - -Travailleur plus d'une dizaine de personnes sur les mmes fichiers peut parfois poser des problmes. Comme un \textit{Update} prcde toujours un \textit{Commit}, il arrive, en priode de travail intense, qu'un autre programmeur russisse faire passer ses modifications entre la succession \textit{Update}-\textit{Commit} d'un autre programmeur. - -\indexfrr{gestion}{centralise}\indexfr{open source}\indexfrr{gestion}{dcentralise} -La gestion des fichiers \textit{SVN} est dite centralise car il existe une seule version officielle de tous les fichiers. Cette configuration n'est pas toujours approprie la gestion du code source de projets open source auxquels participent un grand nombre de programmeurs. La configuration employe est dite dcentralise, ceci signifie qu'il n'existe plus de version officielle mais que chacun possde une version unique et identifie. Il n'y a plus d'opration \textit{Commit} ou \textit{Update} mais simplement l'opration \textit{Merge} qui consiste fusionner les fichiers de deux versions. Avec ce schma, le problme voqu au paragraphe prcdent n'existe plus. - -\subsubsection{Module \codes{pysvn}} \indexmoduleext{pysvn} - -Un module \codes{pysvn}\footnote{tlchargeable depuis l'adresse \httpstyle{http://pysvn.tigris.org/}}\indexmoduleext{pysvn} permet de rcuprer des informations sur un repository et de faire des modifications par l'intermdiaire du langage \python. Grce cela, on pourrait plus facilement piloter \textit{SVN} et faciliter l'excution de tches rcurrentes comme la mise jour chaque nuit de tous les machines de chaque utilisateur. Il faut vrifier lors de l'installation que le module \codes{pysvan} install est cohrent la fois avec la version de \pythons et la version de \textit{SVN} installe. - - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{HTML Help Workshop : construction d'un fichier d'aide} \indexoutil{HTML Help Workshop} \indexoutilz{HTML Help Workshop}{installation} - -La rdaction d'une documentation devrait accompagner toute application destine tout autre utilisateur que le concepteur lui-mme. Un moyen simple est la rdaction de pages HTML. Ces pages peuvent ensuite compiles pour ne former qu'un seul fichier. A cet ensemble est adjoint une table des matires, un indexe, et un moteur de recherche simple. La premire partie du travail est assure par \pythons lui-mme avec le module \codes{pydoc}.\indexmoduleint{pydoc}. La seconde partie est assure par le logiciel \textit{HTML Help Workshop}\footnote{\httpstyle{http://msdn.microsoft.com/en-us/library/ms669985.aspx}}. - -\subsection{Cration automatique d'une documentation avec \codes{pydoc}} - -Le module \codes{pydoc} ne s'utilise pas directement l'intrieur d'un programme \pythons mais en ligne de commande. L'exemple suivant gnre l'aide associe au module \codes{random} et celle du programme \codes{mon\_programme.py} dans le rpertoire courant. -\begin{verbatimx} -c:\python25\python c:\python25\lib\pydoc.py random -c:\python25\python c:\python25\lib\pydoc.py .\mon_programme.py -\end{verbatimx} -Pour l'inclure dans un programme \python, il faut reproduire un appel en ligne de commande grce la fonction \codes{system} du module \codes{os}~:\indexmoduleint{os}\indexfonction{system} -\begin{verbatimx} -import os -os.system (r"c:\python25\python c:\python25\lib\pydoc.py .\mon_programme.py") -\end{verbatimx} -Le nom d'un module standard doit apparatre sans extension, le nom d'un fichier peut apparatre sans extension s'il se trouve dans le rpertoire depuis lequel est lanc l'appel \codes{pydoc}, sinon, il faut mettre son chemin complet avec au moins un symbol~$\backslash$. Le programme suivant cre automatique l'aide associe une liste de fichiers ou de modules, le rsultat est illustr par la figure~\ref{fig_pydoc_sample}. - - -\indexmoduleint{pydoc} -\inputcode{../python_cours/programme/genhelp.py}{gnration automatique de l'aide} - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[width=10.4cm]{\filextel{../python_cours/image/pydoch}} - \\ \hline - \end{tabular}\end{center} - \caption{Exemple gnr avec \codescaption{pydoc}.} - \label{fig_pydoc_sample} - \end{figure} - - -\subsection{Compilation des pages HTML avec \textit{HTML Help Workshop}} - -Les pages gnres par l'exemple prcdents vont tre reprise par l'application \textit{HTML Help Workshop} pour gnrer un fichier d'aide de type \textit{chm}.\indexfrr{extension}{chm} Il est possible d'utiliser cette application de faon classique (voir figure~\ref{fig_hhw}) mais l'objectif de cette section sera de gnrer ce fichier de faon automatique grce un script \python. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=8cm, width=8cm]{\filextel{../python_cours/image/hhw}} - \\ \hline - \end{tabular}\end{center} - \caption{Fentre de l'application \textit{HTML Help Workshop}.} - \label{fig_hhw} - \end{figure} - -Pour cela, il faut construire trois fichiers~: -\begin{enumerate} -\item help.hhp : le fichier de configuration de l'aide\indexfrr{extension}{hhp} -\item help.hhc : le fichier contenant la table des matires (format HTML)\indexfrr{extension}{hhc} -\item help.hhk : le fichier contenant l'indexe (format HTML)\indexfrr{extension}{hhk} -\end{enumerate} - -L'utilisation de ce genre d'outils comme \textit{HTML Help Workshop} est parfois laborieuse, apprendre s'en servir n'a en soi pas beaucoup d'intrt et une fois que la gnration des fichiers \textit{chm} est automatise, il n'est pas rare qu'on oublie leur mode d'emploi. Les paragraphes qui suivent dcrivent sommairement l'application et vous permettront de ne pas lui consacrer trop de temps. Le premier fichier d'extension \textit{hhp} dfinit le projet, un exemple suit, seules les lignes commentes sont importantes. - -\inputcode{../python_cours/programme/exhelp.hhp}{exemple de fichier \textit{hpp} pour \textit{HTML Help Workshop}} - -\indexfr{HTML} -Les fichiers \textit{hhc} et \textit{hhk} sont dfinis avec la mme syntaxe HTML et leur structure est une arborescence. Ces deux fichiers commencent par l'en-tte suivant~: -\begin{verbatimx} - -\end{verbatimx} -Et se concluent par le pied de tte~: -\begin{verbatimx} - -\end{verbatimx} -Chaque lment est compos d'un intitul et d'une page HTML correspondante qui est facultative, ces deux informations vont tre insrs dans le code HTML qui suit~: -\begin{verbatimx} -
  • - - - -\end{verbatimx} -Les niveaux et sous-niveaux sont dfinis par l'instruction \codes{
      } qui permet d'ouvrir une section de niveau infrieure et \codes{
    } de la fermer.\indexhtml{
      }\indexhtml{
    } Appliqu un exemple d'indexe, cela donne~: - -\inputcode{../python_cours/programme/exhelp.hhk}{exemple de fichier \textit{hhk}} - -La dernire tape est de construire un programme \pythons qui construit automatiquement les trois fichiers ncessaires \textit{HTML Help Workshop}. L'exemple suivant est assez simple, il pourrait tre toff notamment en ajoutant l'indexe le nom des classes et de leur mthodes ce qu'il ne fait pas. - -\label{section_chm_programme} -\inputcode{../python_cours/programme/genchm.py}{gnration automatique d'un fichier \textit{chm}} - -\begin{xremark}{problmes de compilation} -Il arrive que les messages d'erreurs de ce logiciel ne soient pas trs explicites. Lors de la compilation du fichier \textit{chm}, il s'intresse aussi toutes les pages dont l'hyperlien dans une des pages incluses dans le fichier \textit{hpp}, c'est pourquoi le nombre de pages final peut tre plus lev que celui des pages recenses. -\end{xremark} - - - -\subsection{Prolongements} - -\indexmoduleext{epydoc}\indexoutil{Graphviz}\indexoutil{Latex}\indexoutil{Miktex}\indexmoduleext{doxypy} -La documentation gnre par le module \codes{pydoc} n'est pas trs agrable lire. D'autres outils permettent d'amliorer la qualit des pages automatiquement gnres et de gnrer d'autres formats que des pages HTML. Le premier est \textit{epydoc}\footnote{\httpstyle{http://epydoc.sourceforge.net/}} qui fonctionne de faon similaire \codes{pydoc} mais dj plus agrable. Le plus rpandu est \textit{Doxygen}\footnote{\httpstyle{http://www.stack.nl/~dimitri/doxygen/}} car il traite la plupart des langages informatique.\indexoutil{Doxygen} Son utilisation fait appel d'autres outils tels que \textit{Graphviz}\footnote{\httpstyle{http://www.graphviz.org/}, cet outil sert reprsenter des graphes.}, \textit{Latex}\footnote{\textit{Latex} n'est pas un outil en soi, c'est un langage permettant de crer des documents usage le plus souvent scientifique. \textit{Miktex} fournit un compilateur sur \textit{Windows} (\httpstyle{http://miktex.org/}).}, ou encore le module \codes{doxypy}\footnote{\httpstyle{http://code.foosel.org/doxypy}}. - - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{InnoSetup : installateur} \indexoutil{InnoSetup} \indexoutilz{InnoSetup}{installation} - -Un installateur rpond au problme~: comment permettre d'autres d'utiliser votre travail en peu de temps~? Une application a souvent besoin de plusieurs fichiers pour fonctionner et ceux-ci doivent respecter une certaine arborescence. \textit{InnoSetup}\footnote{\httpstyle{http://www.jrsoftware.org/isinfo.php}} est une application qui rpond simplement ce problme. Il permet de concevoir un programme excutable (d'extension \textit{exe}) qui recopie aux bons endroits les bons fichiers. Il permet plus prcisment de~: -\begin{enumerate} -\item grouper plusieurs fichiers ensemble en un seul, ces fichiers peuvent provenir de diffrents rpertoires depuis la machine du concepteur -\item recopier ces fichiers des endroits spcifiques sur la machine de l'utilisateur -\item excuter certaines tches avant la premire utilisation -\item construire un sous-menu dans le menu \textit{Dmarrer / Tous les programmes} de \textit{Windows} -\end{enumerate} - -\subsection{Sections \textit{InnoSetup}} - -\subsubsection{section \codes{[Setup]}} - -Toutes ces actions sont dfinies par un fichier texte d'extension \textit{iss}.\indexfrr{extension}{iss} Celui-ci commence par un en-tte dfinissant les options gnrales. -\indexexemples{\textit{InnoSetup}}{} - -\begin{verbatimx} -[Setup] ; nom de la section -AppName=HalPython ; nom de l'application installer -AppVerName=HalPython 1.5.1162 ; numro de version -AppPublisher=Xavier Dupr ; auteur -AppPublisherURL=http://www.xavierdupre.fr/ ; site web -AppSupportURL=http://www.xavierdupre.fr/ ; site web, support -AppUpdatesURL=http://www.xavierdupre.fr/ ; site web, mise jour -DefaultDirName={pf}/HalPython ; emplacement par dfaut sur la machine utilisateur - ; le code {pf} signife le rpertoire \textit{Program Files} -DefaultGroupName=HalPython ; nom par dfaut du sous menu dans - ; Dmarrer / Tous les programmes -OutputDir=c: ; rpertoire o sera crit l'installateur -OutputBaseFilename=setup_HalPython_py25 ; nom de l'installateur ou setup -Compression=lzma ; type de compression, ne pas changer -SolidCompression=yes ; type de compression, ne pas changer -VersionInfoVersion=1.0.0 ; version, ne pas changer -\end{verbatimx} - -\subsubsection{section \codes{[Files]}} - -Ensuite, il faut dfinir les quatre tapes dfinies prcdemment. Les deux premires seront regroupes en une seule section \codes{[Files]} qui indiquera en mme temps l'emplacement d'un fichier chez le concepteur et sa destination chez l'utilisateur. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Files] -Source: "chemin_concepteur"; DestDir: "chemin_utilisateur" ; -Source: "..\hal_dll.dll"; DestDir: "{app}\hal_python" ; autre exemple -\end{verbatimx} - -L'installateur construit par \textit{InnoSetup} demande l'utilisateur de spcifier un chemin d'installation. Le code \textit{app} fait rfrence celui-ci lorsqu'il est utilis dans la dfinition du chemin de destination. - -\subsubsection{section \codes{[Run]}} - -La partie excution permet d'excuter certaines oprations comme des oprations sur les fichiers en lignes de commande, la compilation de fichiers, l'installation d'un module \pythons ou encore l'installation d'autres applications. Par exemple, les lignes suivantes permettent de lancer l'installation du langage \pythons puis de le supprimer (suppression du fichier \textit{python-2.5.2.msi}). -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Run] -Filename: "{win}\system32\msiexec.exe"; Parameters: "/i ""{app}\python-2.5.2.msi"" /qr ALLUSERS=1"; -Filename: "{cmd}"; Parameters: "/c del python-2.5.2.msi"; WorkingDir: "{app}"; -\end{verbatimx} - - -\subsubsection{section \codes{[Icons]}} - -La section \codes{[Icons]} permet d'ajouter un sous-menu dans le menu \textit{Dmarrer / Tous les programmes}. Le nom de ce sous-menu est prcis dans la section \codes{[Setup]}. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Icons] -; liens vers diverses applications -Name: "{group}\PyScripter"; Filename: "{app}\PyScripter.exe"; WorkingDir: "{app}" -Name: "{group}\PyScripter Help"; Filename: "{app}\pyscripter.chm"; WorkingDir: "{app}" -Name: "{group}\Help"; Filename: "{app}\hal_python.chm"; WorkingDir: "{app}" -Name: "{group}\smallest sample with PyScripter"; Filename: "{app}\small_sample.bat"; WorkingDir: "{app}" - -; hyperlien ou url vers un site -Name: "{group}\Website"; Filename: "{app}\hal_python.url" - -; lien vers le dsinstalleur cr automatiquement par InnoSetup -Name: "{group}\uninstall"; Filename: "{uninstallexe}"; WorkingDir: "{app}" -\end{verbatimx} - -Le fichier \codes{hal\_python.url} contient le texte suivant~: -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[InternetShortcut] -URL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -\end{verbatimx} - -La section \codes{[Tasks]} permet de crer un icne sur le bureau reli au sous-menu dfinit auparavant. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; - Flags: checkedonce -\end{verbatimx} - - -\subsubsection{section \codes{[Registry]}} -Cette section permet de modifier les cls de registres de \textit{Windows}. Cela permet de mmoriser le numro de version ou encore le chemin utilis lors d'une installation prcdente. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Registry] -Root: HKLM; Subkey: "SOFTWARE\HalPython\InstallPath"; ValueType: string; ValueName: ""; - ValueData: "{app}"; Flags: uninsdeletekey -Root: HKLM; Subkey: "SOFTWARE\HalPython\Version"; ValueType: string; - ValueName: ""; ValueData: "1.5.1162"; Flags: uninsdeletekey -\end{verbatimx} - - -\subsubsection{section \codes{[Code]}} - -Enfin, si certaines oprations effectuer sont trop complexes pour tre dcrites par ces sections, il est possible de coder des fonctions, d'ajouter des botes de dialogues permettant de choisir des options. Cette dernire possibilit ne sera pas dcrite ici. - -\subsection{Examples} - -\subsubsection{Exemple 1 : installateur pour un module \python} - -L'exemple suivant dfinit un installateur pour un module \pythons construit avec \textit{Boost Python}. Il inclut galement l'installateur de \pythons 2.5 ainsi qu'un diteur de texte. De ce fait, cet unique installateur inclut tout ce qu'il faut pour pouvoir se servir du module. Le rsultat sera un sous-menu dans le menu \textit{Dmarrer / Tous les programmes} incluant diffrents liens dont un ouvrant l'diteur de texte sur un exemple de programme \pythons utilisant le module install. Certaines fonctions ont t ajouts afin que le langage \pythons 2.5 ne soit pas install si celui-ci l'a dj t. - -Tout texte aprs un point virgule est considr comme un commentaire, les instructions des sections \codes{[Run]}, \codes{[Tasks]}, \codes{[Registry]} sont crites sur deux lignes pour des raisons de prsentation mais doivent l'tre sur une seule. - -\inputcode{../python_cours/programme/hal_python.iss}{construction d'un installateur} - -Le fichier \codes{sample.bat} contient la ligne suivante~: -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -PyScripter.exe sample.py -\end{verbatimx} - -\subsubsection{Exemple 2 : mise jour du module} - -L'installateur suivant assure la mise jour du module. Il vite ainsi d'inclure dans le setup de gros fichiers comme l'installateur de \python ou l'diteur de texte. Ce fichier de description est presque identique au prcdent, les parties ne concernant pas le module ont t supprimes et une fonction \codes{InitalizeSetup} a t ajoute. Cette dernire est appele au dmarrage de l'installateur, elle vrifie que tous les lments sont ncessaires au bon fonctionnament du module. En particulier, si \pythons 2.5 n'est pas install, l'installateur affiche un message puis abandonne. - -\inputcode{../python_cours/programme/hal_python_update.iss}{construction d'un installateur de mise jour} - - -\subsection{Quelques trucs en plus} - -\subsubsection{Crer un raccourci} - -Le code suivant permet d'insrer un raccourci dans le sous-menu insr dans \textit{Dmarrer / Tous les programmes}. La premire partie appelle la fonction \codes{GetLnkSciTE} qui cre un raccourci \codes{scite.exe \; sample.y}. La seconde partie consiste insrer une ligne permettant d'ajouter le raccourci au sous-menu. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Code] -function GetLnkSciTE(Param:String): String; -begin - Result := CreateShellLink(ExpandConstant('{app}\SciTE sample.lnk'), - 'Opens SciTE with a sample', - ExpandConstant('{app}\wscite\scite.exe'), - ExpandConstant('"{app}\sample.py"'), - ExpandConstant('{app}'), - '', - 0, - SW_SHOWNORMAL); -end; - -[Icons] -Name: "{group}\smallest sample with SciTE"; Filename: "{code:GetLnkSciTE}"; WorkingDir: "{app}" -\end{verbatimx} - -\subsubsection{Executer des tches plus compliques} - -Il n'est pas vident d'apprendre encore un nouveau langage tel que celui utilis par \textit{InnoSetup}. Pour des tches plus compliques rien n'empche d'excuter un programme \pythons rcuprant les paramtres dont il a besoin sur sa ligne de commande. L'exemple suivant permet de remplacer dans un fichier install une chane de caractres par une autre. Le programme prend trois paramtres sur sa ligne de commande~: le fichier modifier, la chane de caractres remplacer et la chanes qui la remplace. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -def replace_string (file, s1, s2) : - f = open (file, "r") - li = f.readlines () - f.close () - f = open (file, "w") - for l in li : - s = l.replace (s1, s2) - f.write (s) - f.close () - -if __name__ == "__main__" : - import sys - file = sys.argv [1] # fichier modifier - s1 = sys.argv [2] # chane remplacer - s2 = sys.argv [3] # nouvelle chane - replace_string (file, s1, s2) -\end{verbatimx} -% -On cherche remplacer dans le cas prsent la chane \codes{"=pythonw"} par \codes{"=c:\backslash python25\backslash pythonw"}. -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -[Code] -; retourne le chemin du programme pythonw.exe -function GetPythonPathW(Param: String): String; -begin - Result := ''; - Result := ExpandConstant('{reg:HKLM\Software\Python\PythonCore\2.5\InstallPath,|}'); - if Result <> '' then - Result := Result + '\pythonw'; -end; - -; construit les paramtres de la ligne de commande -; "c:\Program Files\HalPython\replace_conf.py" "=pythonw" "=c:\python25\pythonw" -function GetReplaceConf(Param:String):String; -begin - Result := ExpandConstant ('"{app}\replace_conf.py"') - Result := Result + ' ' + ExpandConstant ('"{app}\wscite\python.properties"') - Result := Result + ' "=pythonw"' - Result := Result + ' "=' + GetPythonPathW ('') + '"' ; -end; - -[Run] -; excution de la ligne de commande -Filename: "{code:GetPythonPath}"; Parameters:"{code:GetReplaceConf}"; WorkingDir: "{app}"; -\end{verbatimx} -% -Au final, la ligne de commande excute est la suivante~: -\indexexemples{\textit{InnoSetup}}{} -\begin{verbatimx} -c:\python25\pythonw "c:\Program Files\HalPython\replace_conf.py" "=pythonw" "=c:\python25\pythonw" -\end{verbatimx} - -\begin{xremark}{\codes{pythonw.exe} et \codes{python.exe}} -Dans ce cas, c'est le programme excutable \codes{pythonw.exe} et non \codes{python.exe} qui a t utilis. Ceci vite l'apparition la fentre de la ligne de commande. \indexoutil{pythonw} -\end{xremark} - - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{MoinMoin : wiki} \indexoutil{MoinMoin}\indexoutil{wiki} \label{cgi_definition} - -Un \textit{Wiki} est un outil permettant d'changer facilement de l'information au sein d'une entreprise ou via Internet. Le \textit{Wiki} le plus connu est sans doute \textit{Wikipedia}.\indexfr{Wikipedia} Ce site a pour objectif de crer une encyclopdie que chacun peut modifier. L'intrt d'un \textit{Wiki} dans une entreprise est de pouvoir crer une sorte d'encyclopdie usage interne. A cela s'ajoute la possibilit d'inclure des pices jointes, de garder une trace des diffrentes modifications apportes, ou de grer les droits de chaque utilisateur, tout le monde ne pourra pas lire ou crire ou crer des pages ou certaines pages. L'outil propos ici est \textit{MoinMoin}, c'est un \textit{Wiki} crit en langage \python. - -Un autre avantage d'un \textit{Wiki} est la possibilit d'effectuer une recherche au sein des pages cres dans le \textit{Wiki}. A cette recherche s'ajoute aussi des statistiques comme le nombres de pages cres, le compte de visites de chaque pages, la possibilit d'tre inform d'un changement sur une page. Un \textit{Wiki} a pour objectif de faciliter l'accs l'information d'une entreprise. Pour donner un exemple d'utilisation de \textit{MoinMoin}, je citerai le site \textit{WikiPython}\footnote{\httpstyle{http://wikipython.flibuste.net/}}\indexfr{WikiPython} qui propose de nombreux exemples en franais sur de nombreux sujets. - -Les diffrentes tapes d'installation et de configuration sont extraites de \httpstyle{http://moinmo.in/HelpOnInstalling/ApacheOnWin32} (en anglais). Il est sans doute utile de prciser ce qu'est un script CGI\footnote{CGI : Common Gateway Interface}.\indexfrr{script}{CGI} Ces scripts sont en fait des programmes excuts par un serveur, ils peuvent excuter certaines tches sur le serveur et construire des pages HTML la vole. Typiquement, lorsque le texte d'une page HTML varie (elle affiche l'heure par exemple), cela signifie qu'elle inclut un script CGI qui insre dans la page l'heure actuelle, c'est--dire l'heure laquelle la page a t demande. Concrtement, lorsqu'un internaute se connecte une page HTML~: -\begin{enumerate} -\item Le serveur reoit la requte. -\item Le serveur examine le code de la page HTML. -\item Il commence retourner la page HTML l'internaute. -\item Lors de ce processus, s'il dtecte la prsente d'un script, il l'excute et envoie l'internaute tout ce que le script produit en terme d'affichage. -\item Le serveur a termin sa tche lorsque tous les scripts sont excuts. -\end{enumerate} -Les scripts CGI peuvent tre crit en de nombreux langages, les plus courants sont \textit{PHP} et \textit{JavaScript}. \pythons fait partie galement de la liste des langages utiliss. C'est le cas de \textit{Ruby} aussi. \indexlangage{Ruby} - -\subsection{Installation} \indexoutilz{MoinMoin}{installation} - -La premire tape consiste installer un serveur comme le serveur \textit{Apache},\indexoutil{Apache} cette installation est identique celle du paragraphe~\ref{apache_installation_par} (page~\pageref{apache_installation_par}). L'tape de configuration d'\textit{Apache} requise pour \textit{MoinMoin} pourra s'ajouter celle effectue pour \textit{SVN}. - -La seconde tape consiste installer \textit{MoinMoin}\footnote{Il est disponible l'adresse~: \httpstyle{http://moinmo.in/}}. Une fois tlcharg puis dcompress le fichier \codes{MoinMoin 1.6.3\; tar.gz}\footnote{Le site de \textit{MoinMoin} dconseille l'utilisation de \textit{WinZip} pour dcompresser le fichier tlcharg mais plutt \textit{WinRar} ou \textit{7-Zip}.}, il reste l'installer comme un module \pythons en tapant les instructions suivantes en ligne de commande~: -% -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -C: -cd c:\TEMP\moin-1.6.3 -C:\Python25\python setup.py install --record=install.log -\end{verbatimx} -% -La dernire tape de l'installation consiste crer un rpertoire dans lequel seront placs toutes les informations relatives au \textit{Wiki}. Cela signifie qu'il est possible de crer plusieurs \textit{Wiki}. Les instructions qui suivent sont excuter en ligne de commande, elles supposent que le \textit{Wiki} devra tre crer dans le rpertoire \codes{c:\backslash Moin} et que \pythons a t install dans le rpertoire \codes{c:\backslash Python25}. Dans le cas contraire, il suffit de les adapter. -% -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -cd C:\ -md Moin -md Moin\mywiki -md Moin\mywiki\data -md Moin\mywiki\underlay -cd c:\Python25\share\moin -xcopy data C:\Moin\mywiki\data /E -xcopy underlay C:\Moin\mywiki\underlay /E -copy config\*.* C:\Moin\mywiki\*.* -copy server\*.* C:\Moin\mywiki\*.* -\end{verbatimx} -% -Il reste configurer \textit{Apache} et \textit{MoinMoin} pour que les deux applications communiquent. Par la suite, on supposera que le \textit{Wiki} est cr dans le rpertoire \codes{c:\backslash Moin} et que \pythons a t install dans le rpertoire \codes{c:\backslash Python25}. Dans le cas contraire, il suffit d'adapter ces lignes. - -\subsection{Configuration d'\textit{Apache}} \label{configuration_apache_sql_plus0} \indexoutilz{Apache}{installation} -Voir paragraphe~\ref{configuration_apache_moinmoin} page~\pageref{configuration_apache_moinmoin}. - -\subsection{Configuration de \textit{MoinMoin}} - -Les indications suivantes sont tires du site officiel de \textit{MoinMoin}\footnote{plus prcisment de \httpstyle{http://moinmo.in/HelpOnConfiguration}}. Il y a principalement deux fichiers modifier, le premier gre l'excution du code \pythons au sein de \textit{Apache}, le second gre l'apparence de \textit{MoinMoin}. - - - -\subsubsection{Fichier \codes{moin.cgi}} - -Ce fichier est disponible dans le rpertoire \codes{C:/Moin/mywiki}. Il faut remplacer la ligne~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -#!/usr/env/bin python -\end{verbatimx} -par la ligne~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -#!c:/Python25/python.exe -\end{verbatimx} -% -Cette ligne spcifie om l'interprteur \pythons est disponible sur la machine du serveur. - -\begin{xremark}{pour aller plus loin} -Il est possible, si vous tes courageux, d'optimiser \textit{MoinMoin} en utilisant d'autres types de CGI\footnote{Le rle des CGI est brivement expliqu au paragraphe~\ref{cgi_definition}.}, notamment les \textit{FastCGI} dont l'excution est plus rapide qu'un CGI classique. \indexfr{CGI}\indexfr{FastCGI} Dans ce cas, il faudra penser rpter cette man\oe uvre pour les fichiers du type \codes{moin.*}. -\end{xremark} - - -\subsubsection{Fichier \codes{wikiconfig.py}} - -Ce fichier dfinit l'apparence et les droits d'accs de \textit{MoinMoin}. Aprs l'installation, ce fichier contient de nombreuses lignes commentes concernant les options principales. Tout d'abord, deux options qui permettent \textit{MoinMoin} de dfinir l'emplacement du \textit{Wiki}~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -data_dir = r'C:\Moin\mywiki\data' -data_underlay_dir = r'C:\Moin\mywiki\underlay' -\end{verbatimx} -% -Ensuite, il est prfrable qu'une personne non identifie ne puisse pas dfaut ni attacher une pice jointe, ni dtruire ou renommer une page, pour cela il faut ajouter la ligne~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -actions_excluded = ['DeletePage', 'RenamePage', ] -\end{verbatimx} -% -On dfinit ensuite un "superuser", le seul ayant tous les droits sur \textit{MoinMoin}, le nom d'\textit{admim}\footnote{pour \textit{administrator}} lui est donn (ce n'est pas une obligation)~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -superuser = [u"admin", ] -\end{verbatimx} -% -Les droits utilisateurs sont dfinis par dfaut par la ligne suivante. Par dfaut, le "superuser" peut tout faire~: \label{acl_rights_before_wiki} -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -acl_rights_before = u"admin:read,write,delete,revert,admin" -\end{verbatimx} -% - - - -Il reste dfinir le nom du site et le nom de la premire page~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -sitename = u'NomSite' -page_front_page = u"FirstPage" -\end{verbatimx} - -\begin{xremark}{\codes{wikiconfig.py}, paramtre \codes{url\_prefix\_static} et langue par dfaut} -Il est prfrable de ne pas toucher au paramtre \codes{url\_prefix\_static}, celui-ci ne semble pas fonctionner compltement. Il est prfrable d'utiliser les alias avec \textit{Apache}. Si les termes anglais vous rebutent, il est possible de faire passer une partie des intituls en franais en modifiant le paramtre suivant~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -language_default = 'fr' -\end{verbatimx} -\end{xremark} - - - -Le \textit{Wiki} est maintenant en tat de fonctionner et vous devriez avoir une page correspondant celle de la figure~\ref{wiki_first_page}. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=6cm, width=16cm]{\filextel{../python_cours/image/wiki1}} - \\ \hline - \end{tabular}\end{center} - \caption{Premire page du \textit{Wiki} une fois configur. Son contenu est vide car ce dernier n'a pas encore t prcis. - C'est aussi ce qui s'affiche lorsqu'une page n'existe pas encore mais que le \textit{Wiki} y fait rfrence.} - \label{wiki_first_page} - \end{figure} - -\subsubsection{Scurit, cration d'utilisateurs} - -Il est utile de restreindre maintenant les droits de chaque utilisateurs. La premire chose faire est de crer un utilisateurs administrateurs. Pour cela il faut cliquer sur \textit{Connexion} pour atteindre la page de la figure~\ref{wiki_first_page_connexion}. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=4cm, width=12cm]{\filextel{../python_cours/image/wiki2}} - \\ \hline - \includegraphics[height=3.5cm, width=10cm]{\filextel{../python_cours/image/wiki3}} - \\ \hline - \end{tabular}\end{center} - \caption{Page de connexion, il faut rentrer un login et un mot de passe ou dfinir un nouvel utilisateur en cliquant - sur \textit{UserPreferences} si vous n'avez pas encore de compte. Il est dconseill d'utiliser des accents, - ils peuvent provoquer certains comportements erratiques.} - \label{wiki_first_page_connexion} - \end{figure} - -Une fois qu'un utilisateur administrateur est cr, il faut insrer la ligne suivante dans le fichier \codes{wikiconfig.py}. Elle permet de spcifier que seul l'administrateur (ici dupre) a tous les droits, tout autre utilisateur n'a que le droit de lire les pages sans pouvoir les modifier. Au cas om cet utilisateur essaierait, il tomberait sur la page de la figure~\ref{wiki_first_page_noright}. -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -acl_rights_default = u"dupre:read,write,delete,revert,admin All:read" -\end{verbatimx} - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=3.5cm, width=16cm]{\filextel{../python_cours/image/wiki4}} - \\ \hline - \end{tabular}\end{center} - \caption{Page qui apparat lorsqu'un utilisateur essaye de modifier une page mais qu'il n'en a pas le droit.} - \label{wiki_first_page_noright} - \end{figure} - -\textit{MoinMoin} offre la possibilit de crer des groupes d'utilisateurs, de se connecter un annuaire de type \textit{LDAP} ou \textit{ActiveDirectory}. Le site de \textit{MoinMoin} est assez complet et dcrit tout ce qu'il est possible de faire avec ce \textit{Wiki}\footnote{Tout est y est crit en anglais exclusivement.} Les tapes de configuration prsentes dans ce livre sont assez sommaires et conviennent pour une utilisation au sein d'une entreprise de quelques dizaines d'employs tout au plus et sur un rseau interne. Pour des rseaux de plus en grandes envergures, il est conseill de consulter le site de \textit{MoinMoin}, voire d'opter pour un \codes{Wiki} diffrent. - - - -\subsubsection{Apparence} - -Il est possible de modifier l'apparence du site \textit{Wiki}, la variable \codes{theme\_default} permet de dfinir l'aspect gnral. Il existe trois thmes prdfinis \codes{'classic'}, \codes{'modern'} et \codes{'rightsidebar'}. -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -theme_default = 'modern' -\end{verbatimx} -% -Il est aussi possible de dvelopper son propre thme\footnote{voir l'adresse \httpstyle{http://moinmo.in/MoinDev/ThemeDevelopment}} mais cela requiert un peu de temps ou aller tlcharger un thme existant\footnote{voir l'adresse \httpstyle{http://moinmoin.wikiwikiweb.de/ThemeMarket}} en prenant toutefois soin de vrifier que ce thme fonctionne avec la version de \textit{MoinMoin} installe. - -\subsection{Utilisation sur un rseau d'entreprise} - -Aucune autre configuration n'est a priori ncessaire pour utiliser ce \textit{Wiki} sur le rseau d'une entreprise. La donne de l'adresse IP suffit se connecter au \textit{Wiki} install sur une autre machine. Si cela ne fonctionnait pas, les deux remarques~\ref{remark_firewall} et~ \ref{remark_port_81} page~\ref{remark_port_81} devraient vous rsoudre rsoudre ce problme. - - -\subsection{Ecrire des pages} - -\subsubsection{Cration d'une page} - -Le \textit{Wiki} est maintenant configur, il reste encore savoir comment crire quelques pages commencer par la premire qui est pour le moment l'allure de celle de la figure~\ref{wiki_first_page}. Il suffit de cliquer sur \textit{Create an empty page} pour afficher l'cran de la figure~\ref{wiki_first_page_creation_first}. Le \textit{Wiki} ne manipule que du texte, toute image doit tre traite comme une pice jointe. La syntaxe \textit{Wiki}, simple, permet tout de mme d'afficher des titres, des tableaux, des listes, une table des matires\footnote{voir un rsum en franais de la syntaxe l'adresse \httpstyle{http://moinmo.in/HelpOnMoinWikiSyntax}.}. La figure~\ref{wiki_first_page_creation_first_syntax} donne un court exemple de qu'il est possible de faire avec \textit{MoinMoin}. - - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=3.5cm, width=16cm]{\filextel{../python_cours/image/wiki5}} - \\ \hline - \end{tabular}\end{center} - \caption{Page qui apparat lorsqu'un utilisateur essaye de modifie une page.} - \label{wiki_first_page_creation_first} - \end{figure} - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline -\begin{minipage}{8cm} -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -<> - -= Titre 1 = - -http://www.xavierdupre.fr/mywiki/XavierDupre - -== Titre 1 niveau 2 == -= Titre 2 = - -Affichage d'une liste : - * lment 1 - * lment 2 - * lement 3 : sous liste - * sous lment 1 - * sous lment 2 - * dernier lment de la premire liste - -''italique'' '''gras''' __soulign__ - -une ligne - ----- -\end{verbatimx} -\end{minipage} -& - \includegraphics[height=6.5cm, width=7cm]{\filextel{../python_cours/image/wiki6}} - \\ \hline - \end{tabular}\end{center} - \caption{D'un ct, la syntaxe \textit{MoinMoin}, de l'autre le rendu dans un navigateur.} - \label{wiki_first_page_creation_first_syntax} - \end{figure} - - - -\subsubsection{Ajouter des liens} - -On peut considrer deux types de liens l'intrieur d'un \textit{Wiki}~: les liens externes qui sont une simple adresse internet et les liens internes qui font rfrence une page du \textit{Wiki}. Pour ajouter un lien externe une page, il suffit de l'incoroporer au texte de la page ou entre double crochets si on veut que ce lien apparaisse avec un autre texte. -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -http://www.xavierdupre.fr/mywiki/XavierDupre -[[http://www.xavierdupre.fr/mywiki/XavierDupre|wiki de Xavier Dupr]] -\end{verbatimx} - -Les liens internes sont des rfrences des pages dj crites ou des pages crer si le \textit{Wiki} dtecte que ce lien interne n'existe pas. Un lien interne est un mot contenant deux ou plusieurs majuscule comme \codes{LienInterne} ou une phrase entre crochets comme \codes{[[lien \; interne]]}. - - -\subsubsection{Ajouter des pices jointes} - -L'ajout d'une pice jointe\indexfr{pice jointe} s'effectue en cliquant sur l'intitul \textit{Pice jointe}. Il suffit ensuite d'ajouter le texte \codes{attachment:nom\_de\_la\_piece\_jointe} pour y donner accs tous les lecteurs de la page. - -\subsubsection{Droits spcifiques une page} - -Il est possible d'attribuer des droits spcifiques une page. Le paramtre \codes{acl\_rights\_before} de \codes{wikiconfig.py} (voir paragraphe~\ref{acl_rights_before_wiki}) dfinit les droits par dfaut de chaque page du \textit{Wiki}. Il est nanmoins possible de restreindre l'accs certaines pages du \textit{Wiki}. Par exemple, par dfaut, tout le monde peut lire chaque page mais on voudrait que chaque utilisateurs est un espace rserv inaccessible quiconque autre que lui. Dans ce cas, on ajoutera au dbut du texte de cette page le texte suivant~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -#acl dupre:read,write -\end{verbatimx} -% -Dans ce cas, personne d'autre que l'utilisateur \codes{dupre} ne pourra avoir accs ni en lecture ni en criture la page o est insre cette ligne. Cette ligne crase les droits par dfaut. Le texte de la page peut ensuite tre crit comme n'importe quelle autre page. - - - -\subsection{Script CGI} - -\subsubsection{Script simple} -\indexfr{CGI}\indexfrr{script}{CGI} \indexoutilz{Apache}{configuration CGI} -\textit{MoinMoin} fonctionne base de script CGI~: ce sont des pages HTML entirement produites par des scripts crits en \python. Excut par le ssrveur \textit{Apache}, tout instruction \codes{print} d'un script CGI sera automatiquement envoy au navigateur. Les lignes qui suivent donne un exemple d'introduction cette technique. Il commence par la configuration du serveur \textit{Apache} auquel on indique un nouveau rpertoire dans lequel seront placs des script CGI crits en \python. -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} - - Options FollowSymLinks - AllowOverride None - Order deny,allow - Allow from all - - -Alias /pycgih "C:/Program Files/Apache Software Foundation/Apache2.2/python_cgi" -ScriptAlias /pycgi "C:/Program Files/Apache Software Foundation/Apache2.2/python_cgi" -\end{verbatimx} -% -Dans ce rpertoire, on placera des pages HTML et des scripts CGI. Pour viter de longues adresses URL, on dfinit deux alias diffrents mais dont la cible est le mme rpertoire \codes{python\_cgi}. \textit{Apache} n'accepte pas que deux directives \codes{Alias} et \codes{ScriptAlias} portent le mme nom. -% -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -#!c:/Python25/python.exe -# ligne 1 : emplacement de python (obligatoire) -# ligne 2 : la page ne contiendra que du texte -print "Content-Type: text/plain\n\n" -# premier message au navigateur -print "premier message\n" -\end{verbatimx} -% -Il faut maintenant crer une page HTML qui pointe vers ce script~: -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} - -

    Lien vers un script CGI crit en Python

    -hello.cgi - -\end{verbatimx} -% -Il ne reste plus qu' crire l'adresse de cette page dans le navigateur~: -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -http://localhost/pycgih/index.html -\end{verbatimx} -% -La page affiche fait apparatre un titre suivi d'un unique lien vers le script CGI. Cliquer dessus affiche le message souhait. - - -\begin{xremark}{erreur, premire ligne \codes{\#!c:/Python25/python.exe}} -Il ne faut pas oublier cette premire ligne qui indique \textit{Apache} o trouver l'interprteur \pythons qui lui permettra de comprendre le script. Dans le cas contraire, la page aboutit une erreur. Si cette erreur subsiste toujours mme aprs l'ajout de cette ligne, cela signifie que l'interprteur \pythons n'est pas install cet endroit o que le script a produit une erreur. Dans ce cas, il peut tre utile de remplacer l'extension \codes{cgi} par \codes{py} puis d'excuter le script CGI comme s'il tait un programe \python. -\end{xremark} - -\subsubsection{Script HTML} \indexfr{HTML}\indexcgi{CGI}{plain}\indexcgi{html} - -Le paragraphe prcdent a prsent un script CGI permettant d'afficher du texte gnre par un script \python. Pour mettre en forme ce texte, il faut utiliser la syntaxe HTML et prciser depuis le script que le format de sortie du script est bien du HTML. Pour cela, il faut modifier une ligne du script CGI, \codes{html} remplace \codes{plain}~: -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -print "Content-Type: text/html\n\n" -\end{verbatimx} -% -Par exemple~: -% -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -#!c:/Python25/python.exe -# coding: cp1252 -print "Content-Type: text/html\n\n" -# premier message au navigateur, -# les passages la ligne \n sont sans effet l'affichage -print "\n" -print "premier message en gras\n" -print "" -\end{verbatimx} -% -\begin{xremark}{les accents dans un script CGI} -L'instruction \codes{\#\; \; coding:\; latin-1\; } est toujours ncessaire lorsque le script CGI contient des accents. Dans le cas contraire, l'interprteur \pythons dclenche une exception et le serveur affiche un message d'erreur. -\end{xremark} - - -\subsubsection{Attraper les exceptions} - -Lorsqu'une erreur survient, le texte affich correspond au traitement effectu par le script CGI jusqu' ce que l'erreur se soit produite. Pour pouvoir remonter jusqu' la cause de l'erreur, il est possible d'attraper l'exception engendr par le script et d'afficher les informations relatives cette erreur. Le script suivant gnre volontairement une erreur en excutant une instruction inconnue \codes{stop}. L'exception est alors attrape puis on utilise le module \codes{traceback} pour afficher la ligne et le type d'erreur gnr. \indexmoduleint{traceback} -% -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -#!c:/Python25/python.exe -# coding: cp1252 -print "Content-Type: text/html\n\n" -print "\n" -try: - print "premier message en gras\n" - print "
    dclenchement d'une erreur (instruction inconnue)
    " - stop -except: - import sys - import traceback - print "
    "
    -    traceback.print_exc(file=sys.stdout)
    -    print "
    " -print "" -\end{verbatimx} -% -Le navigateur affiche le message suivant~: -% -\begin{verbatimx} -Traceback (most recent call last): - File "C:/Program Files/Apache Software Foundation/Apache2.2/python_cgi/hello4.cgi", line 8, in - stop -NameError: name 'stop' is not defined -\end{verbatimx} -% -\begin{xremark}{module \codes{traceback} et erreur de syntaxe} -Ce procd ne protge pas le script contre les erreurs de syntaxe, un guillement manquant, une mauvaise indentation ou une parenthse mal ferme. -\end{xremark} - -\subsubsection{Rsum de la syntaxe HTML} \indexfrr{HTML}{syntaxe} - -Il peut tre utile de dcrire trs succintement la syntaxe HTML. Ce langage est un langage balise, c'est--dire que toute information est insre au sein d'une syntaxe qui ressemble ~: -\begin{verbatimx} - .... -\end{verbatimx} -% -\indexfrr{HTML}{balise} -Les balises peuvent tre crites avec des minuscules ou des majuscules, le langage HTML ne fait pas la diffrence. Toute page HTML s'crit de la forme~: -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} - - -.... entte de la page, n'est pas affich, il est possible d'y dfinir -.... des feuilles de styles pour un affichage amlior -.... ou la dfinition de nouvelles balises -.... la ligne - -.... permet de dfinir un jeu de caractres incluant les accents franais - - -.... contenu de la page - - -\end{verbatimx} -% -Le contenu de la page doit figurer entre les balises \codes{} et \codes{}. La table~\ref{balises_html_table} regroupe les balises de style les plus utilises et la table~\ref{balises_html_table2} des balises courantes de prsentations. Les balises cites dans ces tables permettent de prsenter des rsultats au format HTML. Pour des prsentations plus sophistiques, une recherche sur Internet donnera la plupart du temps une rponse\footnote{voir galement \httpstyle{http://fr.wikipedia.org/wiki/HTML}}. Le langage tant en perptuelle volution, les possibilits offertes ne cessent de s'tendre. \indexhtml{}\indexhtml{
    }\indexhtml{
    }\indexhtml{}\indexhtml{}\indexhtml{}\indexhtml{

    }\indexhtml{

    }\indexhtml{

    } - - -\begin{table}[ht] -\begin{center}\begin{tabular}{|l|p{8cm}|} \hline -\textbf{balises} & \textbf{effet} \\ \hline -\codes{} & commentaires, ces informations ne sont pas affiches par le navigateur\\ \hline -\codes{

    } & titre de premier niveau \\ \hline -\codes{

    } & titre de second niveau \\ \hline -... & ... \\ \hline -\codes{
    } & aller la ligne \\ \hline -\codes{
    } & tracer une ligne horizontale\\ \hline -\codes{ } & gras \\ \hline -\codes{ } & italique \\ \hline -\codes{ } & soulign \\ \hline -\codes{ } & barr \\ \hline -\end{tabular}\end{center} -\caption{Balises HTML relatives la mise en forme de caractres.} -\label{balises_html_table} -\end{table} - - -\indexhtml{}\indexhtml{}\indexhtml{name=}\indexhtml{src=}\indexhtml{href=}\indexhtml{

    }\indexhtml{}\indexhtml{} -\indexhtml{
    }\indexfrr{HTML}{attribut}\indexhtml{border=} - -\begin{table}[ht] -\begin{center}\begin{tabular}{|l|p{8cm}|} \hline -\textbf{balises} & \textbf{effet} \\ \hline -\codes{} texte \codes{} & lien, url dsigne l'hyperlien, le texte afficher par le navigateur est situ entre les balises\\ \hline -\codes{} & poser une ancre\\ \hline -\codes{} texte \codes{} & lien vers une ancre l'intrieur d'une page\\ \hline -\codes{ } & lien vers une image, les attributs \codes{width} et \codes{height} pour modifier la taille de l'image - lorsqu'elle est affiche. \\ \hline -\codes{

    } & paragraphe \\ \hline -\codes{
    } & insertion d'un tableau, l'attribut \codes{border} permet de prciser l'paisseur des bords. - \codes{} \\ \hline -\codes{} & insertion d'une ligne dans un tableau \\ \hline -\codes{} & insertion d'une case dans un tableau \\ \hline -\codes{} & insertion d'une case dans un tableau \\ \hline -\codes{
    } & cration d'une liste \\ \hline -\codes{
  • } & insertion d'un intitul au sein d'une liste\\ \hline -\end{tabular}\end{center} -\caption{Balises HTML relatives la mise en page. Le nom du fichier suit le mot \codescaption{src} - dans la syntaxe, \codescaption{}, - \codescaption{src} est appel un attribut. les valeurs associes aux attributs sont toujours entoures de guillemets. - Lorsqu'il n'y a rien entre deux balises, l'criture peut tre courte en \codescaption{}. - } -\label{balises_html_table2} -\end{table} - - - -\subsubsection{Appeler une page avec des paramtres} - -Les programmes \pythons sont capables d'accepter des paramtres lorsqu'ils sont excuts en ligne de commande. Ce mcanisme existe galement en ce qui concernent les pages HTML. Cela consiste faire un URL d'un point d'interrogation puis d'une suite de couple \codes{param=valeur} spar par le symbole~$\&$. -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -http://URL?param1=valeur1¶m2=valeur2&... -\end{verbatimx} -% -Le programme suivant rcupre la valeur de ces paramtres. -% -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -#!c:/Python25/python.exe -# coding: cp1252 -print "Content-Type: text/html\n\n" -print "\n" -import cgi -par = cgi.FieldStorage() -if len (par) == 0 : - print " aucun paramtre cette page " -else : - print "liste des paramtres
    " - print """
  • """ - for p in par : - print "" - name = str (p) - value = par.getvalue (name) - print "" - print "" - print "
    ", name, "", value, "
    " -print "" -\end{verbatimx} - -\subsubsection{Formulaires} \indexfrr{HTML}{formulaire} - -Le langages HTML donne la possibilit de construire des formulaires puis de rcuprer les donnes saisies par l'internaute. Bien souvent, la page qui affiche le formulaire est un script CGI capable de traiter les donnes qu'il s'envoie lui-mme. L'utilisateur slectionne l'adresse~: -\begin{verbatimx} -http://localhost/pycgi/pyform.cgi -\end{verbatimx} -Puis le formulaire, lorsque l'utilisateur appuie sur \textit{Envoyer}, appelle l'URL suivant~: -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -http://localhost/pycgi/pyform.cgi?nom=dupre&prenom=xavier -\end{verbatimx} -C'est ce que fait le script CGI suivant. Il affiche d'abord le formulaire de la figure~\ref{forulaire_python_html}. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=2cm, width=5cm]{\filextel{../python_cours/image/pyform1}} - \\ \hline - \end{tabular}\end{center} - \caption{Exemple de formulaire au format HTML engendr par un script CGI crit en \python.} - \label{forulaire_python_html} - \end{figure} -\indexexemples{\textit{Apache}, CGI}{} -\begin{verbatimx} -#!c:/Python25/python.exe -# coding: cp1252 -print "Content-Type: text/html\n\n" -print "\n" -def print_form () : - # cration du formulaire avec deux champs nom et et prenom - print """ -
    -

    -
    -
    - -

    -
    - """ - -import cgi -par = cgi.FieldStorage () -if len (par) == 0 : - # s'il n'y a aucun paramtre, on affiche le formulaire - print_form () -else : - # sinon, cela signifie que le formulaire a rappel le script CGI - # avec des paramtres et le traitement suit une direction diffrente - # ici, cela consiste afficher les informations reues en gras - nom = par.getvalue ("nom") - prenom = par.getvalue ("prenom") - print "Votre nom est ", nom, " et votre prnom ", prenom, "" -print "\n" -\end{verbatimx} - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{SQL} \indexlangage{SQL}\indexoutil{SQL} \indexfr{SQL} - -Le langage SQL est devenu incontournable pour quiconque souhaite stocker, consulter de grandes quantit de donnes. Les paragraphes qui suivent ne feront que prsenter sommairement le langage SQL, il s'agit ici de l'utiliser via un programme \pythons plutt que de le matriser. - -\subsection{Les bases de donnes} - -Le langage SQL est li ce qu'on appelle les \emph{bases de donnes}.\indexfr{base de donnes} C'est simplement un ensemble de tableaux ou plutt \emph{table}.\indexfr{table} Une table est dfinie par un nombre de colonnes, chacune porte un nom et ne contient qu'un type donn d'information. Par exemple, lorsqu'on dcrit un lve dans le systme informatique d'une cole, on retiendra par exemple~: \indexfrr{SQL}{table} -\begin{footnotesize}\begin{center}\begin{tabular}{l|l|l} -information & nom & type \\ \hline -un numro & num & nombre entier \\ -son nom & nom & chane de caractres (30 maximum) \\ -son prnom & prenom & chane de caractres (30 maximum) \\ -sa date de naissance & date & date \\ -son adresse & adresse & chane de caractres (100 maximum) \\ -son genre & genre & boolen \\ -sa nationalit & codepays & un nombre entier \\ -sa classe & classe & nombre entier -\end{tabular}\end{center}\end{footnotesize} -% -Cette table, qu'on appelle \codes{ELEVE}, sera reprsente sous la forme d'un tableau. Le numro permet de dsigner chaque lve plus facilement dans le systme informatique que par son nom et son prnom, il permet aussi de distinguer portant mme nom et prnom. Ce numro porte souvent le nom d'\emph{index}. -\begin{footnotesize}\begin{center}\begin{tabular}{|l|l|l|l|l|l|l|l|} \hline -num & nom & prenom & date & adresse & genre & codepays & classe \\ \hline -1 & dupre & xavier & 11/08/1975 & ... paris & True & 33 & 19 \\ \hline -2 & dupre & gilles & 24/12/1946 & ... charleville & True & 33 & 56 \\ \hline -\end{tabular}\end{center}\end{footnotesize} -% -Le pays est entier, on aurait pu choisir une chane de caractres galement. Toutefois, il est possible de dfinir une seconde table qu'on appelle \codes{PAYS} avec la liste des pays et le numro qui leur sont attribus. -\begin{footnotesize}\begin{center}\begin{tabular}{|l|l|} \hline -pays & codepays \\ \hline -France & 33 \\ \hline -Royaume-Uni & 44 \\ \hline -\end{tabular}\end{center}\end{footnotesize} -% -Lorsqu'on cherche des lves d'une certaine nationalit sans connatre son code, il suffit de chercher d'abord le code dans la table \codes{PAYS} puis de chercher les lves ayant ce code dans la table \codes{ELEVE}. En langage SQL\footnote{Il n'est pas tenu compte des passages la ligne, ils apportent plus de lisibilit.}, la premire requte s'ecrit~: \indexfrr{SQL}{requte} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -SELECT codepays -FROM PAYS -WHERE pays = 'France' -\end{verbatimx} -% -La seconde requte utilise les rsultats de la premire, en lanage SQL, cela donne~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -SELECT num,nom,prenom -FROM ELEVE -WHERE codepays IN ( - SELECT codepays - FROM PAYS - WHERE pays = 'France' - ) -\end{verbatimx} -% -A ces deux tables, on ajoute une table des matires enseignes~: -\begin{footnotesize}\begin{center}\begin{tabular}{l|l|l} -information & nom & type \\ \hline -numro & num & nombre entier \\ -matire & matiere & chane de caractres (30 maximum) \\ -niveau & niveau & nombre entier -\end{tabular}\end{center}\end{footnotesize} -% -Puis une table des notes attribues~: -\begin{footnotesize}\begin{center}\begin{tabular}{l|l|l} -information & nom & type \\ \hline -numro lve & nume & nombre entier \\ -numro matire & numm & nombre entier \\ -note & note & nombre rel -\end{tabular}\end{center}\end{footnotesize} -% -Si on relie les colonnes portant la mme information, on aboutit au graphe de la figure~\ref{graphe_figure_sql_}. Ces liens illustrent le concept de \emph{base de donnes relationnelle}.\indexfrr{base de donnes}{relationnelle} Il serait possible de reprsenter toutes ces donnes sous la forme d'un unique tableau mais il aurait beaucoup de colonnes et autant de lignes que de notes. Autrement dit, les mmes informations sont prsentes en de nombreux endroits. Pour viter la redondance d'un tel systme, il faut scinder ce tableau en autant de tables que ncessaire pour faire disparatre la la redondance. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=3cm, width=12cm]{\filextel{../python_cours/image/sql1}} - \\ \hline - \end{tabular}\end{center} - \caption{Graphe illustrant les bases de donnes relationnelles, - les champs relis entre eux ont le mme sens. Un numro d'lve - dsigne aussi bien un lve dans la table \codescaption{ELEVE} - que dans la table \codescaption{NOTE}. Si on connat le numro d'un lve, - on connat galement toutes les autres informations le concernant, c'est pourquoi, - dans la table \codescaption{NOTE}, on - inscrit que son numro. Toute autre information serait superflue.} - \label{graphe_figure_sql_} - \end{figure} - -Le langage SQL permet de recherche des informations dans cet ensemble de tables. Par exemple, la requte suivante permet de construire la liste des lves suivi de la moyenne de leurs note en franais~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -SELECT nom,prenom,AVG(note) FROM ELEVE,NOTE -WHERE num = nume and - numm IN ( SELECT num FROM MATIERES WHERE matiere = 'franais' ) -GROUP BY nume -\end{verbatimx} - - -Le chapitre suivant montrera comment crer ces diffrentes tables, y insrer des lignes (ou enregistrements), lancer des requtes. - -\subsection{Utiliser une base de donnes} \label{sql_sqlite3_parag} - -La faon la plus simple d'utiliser une base de donnes est d'utiliser l'application \textit{SQLite}\footnote{\httpstyle{http://www.sqlite.org/}}.\indexoutil{SQLite} C'est d'autant plus avantageux que ce module est fourni avec l'installation standard de \python. La base de donnes, qui est un ensemble de plusieurs tables, est en fait stocks dans un unique fichier. On lit et on crit dans ce fichier grce au module \codes{sqlite3}.\indexmoduleint{sqlite3} Et l'unique moyen d'crire, de lire, de consulter est d'utiliser des requtes~SQL. Par exemple, la cration de la table \codes{ELEVE} se fait grce la requte suivante~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -CREATE TABLE ELEVE ( - num integer primary key, - nom varchar (30), - prenom varchar (30), - date date, - adresse varchar (100), - codepays integer, - classe integer) -\end{verbatimx} -% -\indexsql{CREATE}\indexsql{TABLE} -Le mot-cl \codes{primary\; key}\indexsql{primary\; key} permet d'indiquer au langage SQL qu'il peut utiliser ce champ comme un index~: il n'y aura jamais deux lves avec des numros identiques. C'est aussi une cl qui est attribue automatiquement par le langage SQL. Si une table contient un tel champ, sa consultation est plus rapide. Il ne reste plus qu' excuter cette requte grce au module \codes{sqlite3}~: -% -\inputcode{../python_cours/programme/sql_1.py}{cration d'une table avec \codesindex{sqlite3}} -% -La premire instruction permet d'ouvrir une connexion la base de donnes, d'indiquer qu'on s'en sert. La seconde instruction permet de crer ce qu'on appelle un curseur.\indexfrr{SQL}{curseur} Cela permet d'avoir un accs la base qui autorise des accs simultans en nombre limit. La troisime instruction excute la requte proprement dite. -% -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -cur.execute ("CREATE TABLE NOTE (nume integer, numm integer, note double)") -cur.execute ("CREATE TABLE MATIERES (num integer, matiere varchar (30))") -cur.execute ("CREATE TABLE PAYS (codepays integer, pays varchar (30))") -\end{verbatimx} -% -Il faut maintenant insrer des valeurs dans chacune des tables~: -\inputcode{../python_cours/programme/sql_1.py}{insertion de valeurs dans une table \codesindex{sqlite3}} -% -Il ne faut pas oublier l'instruction \codes{cx.commit ()} qui met jour la base de donnes. Sans cette instruction, les tables ne sont pas modifies et pendant l'excution de cette instruction, toutes les autres requtes sont momentanment interrompues le temps que la modifications de la base soit effective. Le programme suivant permet de vrifier que les modifications ont bien t prises en compte~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import sqlite3 as SQL -cx = SQL.connect("madatabase.db3") -cur = cx.cursor() -cur.execute("select * from ELEVE") -for row in cur.fetchall(): print row -\end{verbatimx} -Il affiche\footnote{Le symbol \codesnote{u} devant les chanes de caractres indique qu'elles sont codes au format unicode\indexfr{unicode}\indexfrr{SQL}{unicode} et que les accents sont pris en compte.}~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -(1, u'dupre', u'xavier', u'11/08/1975', u'---- paris', 33, 19) -(2, u'dupre', u'gilles', u'24/12/1946', u'---- charleville', 33, 56) -\end{verbatimx} -% -Il reste insrer d'autres valeurs dans ces tables\footnote{En langage SQL, le mot-cl \codesnote{UPDATE} sert modifier un enregistrement.\indexsql{UPDATE}}~:\indexsql{SELECT}\indexsql{INSERT}\indexsql{INTO}\indexsql{VALUES}\indexsql{FROM} -% -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -cur.execute ("INSERT INTO PAYS (codepays, pays) VALUES (33, 'France')") -cur.execute ("INSERT INTO PAYS (codepays, pays) VALUES (44, 'Royaume-Uni')") -cur.execute ("INSERT INTO MATIERES (matiere, num) VALUES ('franais', 1)") -cur.execute ("INSERT INTO MATIERES (matiere, num) VALUES ('mathmatiques', 2)") -cx.commit () -\end{verbatimx} -% -Il ne reste plus qu' ajouter des notes~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -note = [(1, 1, 12), (1, 1, 14), (1, 2, 16), (1, 2, 8), (1, 2, 12), \ - (2, 1, 8), (2, 1, 9), (2, 2, 11), (2, 2, 8), (2, 2, 12)] -for n in note : - req = "INSERT INTO NOTE (nume,numm,note) VALUES " + str (n) - cur.execute (req) -cx.commit () -\end{verbatimx} -% -Le programme suivant permet de dterminer la liste des prnoms des lves suivi de la moyenne de leurs notes~: \indexsql{GROUP \; BY}\indexsql{AVG} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -req = """ -SELECT nom,prenom,AVG(note) FROM ELEVE,NOTE -WHERE num = nume and - numm IN ( SELECT num FROM MATIERES WHERE matiere = 'franais' ) -GROUP BY nume -""" -cur.execute (req) -for row in cur.fetchall(): print row -\end{verbatimx} -Le rsultat de la requte donne pour notre exemple~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -(u'dupre', u'xavier', 13.0) -(u'dupre', u'gilles', 8.5) -\end{verbatimx} -% -En ajoutant une condition avec le mot-cl \codes{HAVING}, il est possible de ne retourner que la liste des lves ayant la moyenne~: \indexsql{HAVING} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -req = """ -SELECT nom,prenom,AVG(note) FROM ELEVE,NOTE -WHERE num = nume and - numm IN ( SELECT num FROM MATIERES WHERE matiere = 'franais' ) -GROUP BY nume -HAVING AVG(note) >= 10 -""" -cur.execute (req) -for row in cur.fetchall(): print row -\end{verbatimx} - - - -\subsection{Utiliser un serveur de base de donnes} - - -Le module \codes{sqlite3} propose en quelque sorte de stocker des informations de faon plus intelligente qu'un simple fichier texte puisqu'il met disposition des outils permettant de consulter rapidement ces informations sans avoir lire intgralement les donnes pour les mettre dans la mmoire de l'ordinateur au travers de listes par exemple. Toutefois, les informations sont localises dans un unique fichier et elles ne sont pas faciles partages travers un rseau. - -Un serveur de bases de donnes offre les mmes services au niveau du stockage et de la consultation des donnes mais il permet de partager ces informations avec quiconque a accs ce serveur. Le serveur de base de donnes organise la mise en commun de grandes volumes d'informations. Un serveur de bases de donnes est un serveur au mme titre que l'application \textit{Apache}~: c'est une application qui tourne en permanence, de prfrence sur un ordinateur entirement ddi ce service, et qui attend les requtes des utilisateurs provenant de tous les utilisateurs ayant la possiblit de se connecter ce serveur. - - -\subsubsection{Installer un serveur de base de donnes sous \textit{Windows}} \indexoutilz{MySQL}{installation} - -Les paragraphes qui suivent dcrivent l'installation de serveur \textit{MySQL}. Il est parfois plus simple d'utiliser l'application \textit{EasyPHP}\footnote{\httpstyle{http://www.easyphp.org/}}\indexoutil{EasyPHP} qui en simplifie l'installation lorsqu'elle est coupl avec le serveur \textit{Apache} (voir galement le paragraphe~\ref{apache_installation_par}). - -Il existe de nombreux serveurs de base de donnes. Les plus connus sont \textit{Microsoft SQL Server},\indexoutil{Microsoft SQL Server} \textit{Oracle},\indexoutil{Oracle} \textit{Sybase}.\indexoutil{Sybase} Parmi les serveurs gratuits, on trouve \textit{MySQL},\indexoutil{MySQL} ou encore \textit{PostGreSQL}.\indexoutil{PostGreSQL} Ces applications sont souvent regroupes sous le terme de \textit{SGBD}\indexfr{SGBD} ou encore \textit{Systme de gestions de base de donnes}. - -L'installation de \textit{MySQL}.\indexoutil{MySQL} n'est pas trs complique. Il faut dans un premier temps tlchercher \textit{MySQL}\footnote{\httpstyle{http://dev.mysql.com/downloads/mysql/5.0.html\#downloads}} puis suivre les instructions de la figure~\ref{mysql_installation_figure}. Il est tout de mme possible de changer les paramtres de la configuration sans avoir refaire l'installation, il suffit d'aller dans le sous-menu ajouter par \textit{MySQL} dans le menu \textit{Dmarrer / Tous les programmes}. - - \begin{figure}[H] - \begin{center}\begin{tabular}{|c|c|c|}\hline - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql1}} & - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql2}} & - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql3}} \\ \hline - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql4}} & - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql5}} & - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql6}} \\ \hline - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql7}} & - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysql8}} & \\ \hline - \end{tabular}\end{center} - \caption{L'installation de \textit{MySQL} fait intervenir une petite dizaine d'crans qui se succdent. - Chacun d'eux propose quelques - options d'installation que l'utilisateur doit choisir. Voici les - choix pour une utilisation sur une machine de bureau qui n'est - pas exclusivement rserv \textit{MySQL} et qui autorise une dizaine - de connexion simultane. Cette base n'est donc pas - configure pour un usage intense. Les derniers crans font rfrence la scurit. - Il est conseill de dfinir un mot de passe - \textit{root} ou administrateur. C'est le seul utilisateur ayant tout pouvoir sur la gestion du systme.} - \label{mysql_installation_figure} - \end{figure} - -Il faut maintenant installer un second morceau qui est le pilote \textit{ODBC} pour \textit{MySQL}\footnote{Il est tlchargeable l'adresse \httpstyle{http://dev.mysql.com/doc/refman/5.0/fr/myodbc-windows-binary-installation.html}.}. Il n'y a cette fois-ci rien configurer et tout se passe presque sans intervention. Cette seconde tape est facultative mais elle rend l'criture de programmes plus facile et surtout indpendante du serveur de base de donnes choisie. - -Avant d'utiliser \pythons pour lancer des requtes, le serveur nouvellement install est entirement vide et il faut d'abord crer ce qu'on appelle une \emph{database}.\indexfr{database} C'est principalement un ensemble de tables. Pour cela, il faut cliquer sur l'intitul \textit{MySQL Command Line client} du menu \textit{Dmarrer / Tous les programmes / MySQL / MySQL Server 5.0}. Il vous est d'abord demand un mot de passe, celui renseign lors de l'installation. Ensuite il faut taper la ligne suivante~: \label{creation_database_paragraphe} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -CREATE DATABASE datatest ; -\end{verbatimx} -L'instruction ne devrait pas retourner d'erreur et partir de ce moment, la database \codes{datatest} est cre. Il sera alors possible d'y connecter un pilote ODBC pour s'en servir dans un programme \python. - -Il reste une dernire installation effectuer, celle du module \codes{pywin32}\footnote{\httpstyle{https://sourceforge.net/projects/pywin32/}}\indexmoduleext{pywin32} qui permet d'utiliser une connexion ODBC. Son installation utilise un programme excutable et ne requiert aucune intervention. - - - -\subsubsection{Configurer une connexion ODBC sous \textit{Windows}} - -\indexfr{ODBC}\indexfr{Object Database Connectivity} -Il existe de nombreux modules \pythons qui permet de se connecter directement un serveur de base de donnes particulier comme le module \codes{MySQLdb}\footnote{\httpstyle{http://sourceforge.net/projects/mysql-python}}\indexmoduleext{MySQLdb} qui accde au serveur \textit{MySQL}. Mme si cet accs est le plus rapide, l'inconvnient de ce systme est qu'il faut utiliser un module diffrent pour chaque serveur de bases de donnes\footnote{On trouve l'adresse \httpstyle{http://www.pygresql.org/} le module pour le serveur \textit{PostGreSQL}.}. - -Il existe un moyen d'homogniser les accs aux serveurs en ajoutant une couche intermdiaire appele \textit{ODBC} ou \textit{Object Database Connectivity}. Grce ce systme, le code ncessaire l'utilisation d'un serveur ne dpend plus du systme de base de donnes utiliss. Celui-ci peut tre \textit{MySQL} ou \textit{Microsoft SQL Server} ou encore un fichier texte, \textit{Excel}, une base de donnes \textit{Access}. Il suffit pour cela de dclarer ce pilote ODBC au systme d'exploitation \textit{Windows}. Il faut pour cela aller dans le panneau de configuration, icne \textit{Outils d'administration} puis choisir \textit{Database ODBC}. On tombe alors sur une fentre du type de celle prsente la figure~\ref{ODBC_window_foigure}. La configuration du pilot ODBC suit les instructions de la figure~\ref{ODBC_window_foigure_config}. - - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=4cm, width=5cm]{\filextel{../python_cours/image/odbc}} - \\ \hline - \end{tabular}\end{center} - \caption{Fentre grant les accs ODBC sous \textit{Windows}. - La fentre montre quatre connexions ODBC disponibles de types diffrents. - Il suffit de cliquer sur le bouton \textit{Add} pour ajouter une connexion ODBC et ouvrir - un accs une nouvelle source, - que ce soit un fichier texte, un fichier \textit{Excel}, un serveur,~...} - \label{ODBC_window_foigure} - \end{figure} - - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[height=5cm, width=11cm]{\filextel{../python_cours/image/mysqlodbc}} & - \includegraphics[height=5cm, width=5.5cm]{\filextel{../python_cours/image/mysqlodbc2}} \\ \hline - \multicolumn{2}{|c|}{ \begin{minipage}{16cm} Concernant la connexion ODBC~: - \begin{itemize} -\item Son nom est \textit{mysqlperso}, il est possible de le changer. -\item Le server est \textit{localhost}, c'est la machine locale, si c'est une machine distante mais connecte au rseau - interne, il faut ici prciser son adresse~IP. -\item Le port est par dfaut 3306, dans un cas classique, ce paramtre est dj renseign. -\item Le nom d'utilisateur et le mot de passe sont un de ceux dfinis sur le serveur de base de donnes, - si aucun utilisateur n'a t ajout, alors, il faut choisir l'utilisateur \textit{root} et le mot de passe - renseign lors de l'installation (dans ce cas \textit{admin}). -\item Enfin, il faut indiquer un nom de database qui existe sur le serveur de base de donnes. (Pour la crer, voir le - paragraphe~\ref{creation_database_paragraphe} (page~\pageref{creation_database_paragraphe}). -\end{itemize}\end{minipage} } - \\ \hline - \end{tabular}\end{center} - \caption{La configuration d'une connexion ODBC se passe en - deux tapes, la premire consiste ajouter une connexion en cliquant sur - le bouton \textit{Add} de la premire fentre. La seconde fentre - permet de choisir le type de connexion, dans le cas de - \textit{MySQL}, il faut choisir \textit{MySQL ODBC 5.1 Driver}. - La troisime fentre dfinit les paramtres de la connexion~: - Le bouton \textit{Test} permet de s'assurer que ces paramtres sont bien valides. - } - \label{ODBC_window_foigure_config} - \end{figure} - -\subsubsection{Utilisation d'un serveur de base de donnes} - -En utilisant une connexion ODBC, les lignes crites au paragraphe~\ref{sql_sqlite3_parag} ne diffrent except celle qui ouvre la connexion ODBC qui s'effectue avec un module diffrent. Le module utliser devient \codes{odbc}.\indexmoduleint{odbc} La cration d'une table fait appel au script suivant~: -% -\inputcode{../python_cours/programme/odbc_1.py}{connexion ODBC, cration d'une table} -% -L'ajout de donnes diffre un peu de \codes{sqlite3} car le serveur SQL requiert une valeur par dfaut pour la colonne \codes{num} alors qu'elle tait renseign automatiquement par \codes{sqlite3}. Le langage SQL est en principe le mme d'un serveur SQL l'autre mais il arrive parfois que certains logiciels proposent des spcificits non comprhensibles par un autre SGBD. Par exemple, le format des dates par dfaut n'est pas le mme sur \textit{MySQL}~: -% -\inputcode{../python_cours/programme/odbc_2.py}{connexion ODBC, ajout de donnes} -% -Pour lancer une requte, le code reste le mme~: -% -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import odbc -cx = odbc.odbc("mysqlperso") -cur = cx.cursor() -cur.execute ("SELECT * from ELEVE") -for row in cur.fetchall () : - print row -\end{verbatimx} -% -\begin{xremark}{SGBD et les dates} -La gestion des dates peut tre diffrente d'un SGBD l'autre, avec \textit{MySQL}, elles apparaissent sous forme d'objets. Pour pouvoir l'afficher, il faut remplacer la dernire du programme prcdent par~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} - print [ str (r) for r in row ] -\end{verbatimx} -\end{xremark} -% -Mise part la connexion, les autres requtes et le code \pythons les excutant extraits des exemples dvelopps au paragraphe~\ref{sql_sqlite3_parag} seront identiques avec \textit{MySQL}. - - -\subsubsection{ODBC et script CGI} - -\textbf{Problme de mot de passe} - -\indexfrr{ODBC}{mot de passe}\indexfrr{ODBC}{login}\indexfrr{ODBC}{password} - -Lorsqu'on cherche se connecter une connexion ODBC, celle-ci requiert parfois un login et un mot de passe. Par exemple, les deux lignes qui suivent permettent d'ouvrir une connexion ODBC vers un serveur de type \textit{SQL Server} de \textit{Microsoft}. \indexfr{\textit{Microsoft}}\indexoutil{Microsoft SQL Server} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import odbc -cx = odbc.odbc("odbc_sql_server") -\end{verbatimx} -% -L'excution du programme retourne le message suivant annonant l'impossibilit de l'ouverture de la connexion~: -% -\begin{verbatimx} -dbi.operation-error: [Microsoft][ODBC SQL Server Driver][SQL Server]Login failed for user ''. -The user is not associated with a trusted SQL Server connection. in LOGIN -\end{verbatimx} -% -Dans le cas, il faut rpter le login et le mot de passe utilis lors de la configuration de la connexion ODBC comme ceci~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import odbc -cx = odbc.odbc("odbc_sql_server/login/password") -\end{verbatimx} -Une autre syntaxe comme celle qui suit est galement correcte~: -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -cx = odbc.odbc("DSN=odbc_sql_server;UID=login;PWD=password") -\end{verbatimx} - -\textbf{Service \textit{Apache}} \indexfrr{service}{Windows}\indexfrr{Windows}{service}\indexoutilz{Apache}{service} \label{configuration_apache_sql_plus} -\indexoutilz{Apache}{installation} - -Il arrive aussi que la connexion ODBC ne fonctionne pas car la table ou le serveur SQL n'est pas trouv. Lorsqu'on excute le script CGI comme un programme \python, celui-ci fonctionne parfaitement. Ceci s'explique par le fait que le serveur \textit{Apache} fonctionne avec un nom d'utilisateur qui ne lui permet pas de crer une connexion ODBC. Il existe deux faons de rsoudre ce problme. La premire consiste configurer le service \textit{Apache} et le relancer avec le bon login et le bon mot de passe. La seconde option consiste ne plus lancer le serveur \textit{Apache} comme un service \textit{Windows} mais comme un programme depuis une fentre de commande. Il faut donc excuter les trois lignes qui suivent~: -\indexexemples{\textit{Apache}}{} -\begin{verbatimx} -cd c:\Program Files\Apache Software Foundation\Apache2.2\bin -httpd -k stop -httpd -\end{verbatimx} -La premire ligne permet de se placer dans le rpertoire d'\textit{Apache}. La seconde arrte l'excution du serveur \textit{Apache} en tant que service, la dernire ligne redmarre le serveur \textit{Apache} en tant que programme indpendant. En contrepartie, il ne faut pas fermer la fentre de commande \textit{Windows} moins de vouloir arrter le serveur \textit{Apache}. Cette solution fonctionne localement, il est possible que le serveur ne soit plus accessible depuis une autre machine connecte sur le mme rseau interne. - -Une autre option consiste donner au service \textit{Apache} l'accs au serveur de base de donnes. Pour cela, il faut associer au serveur \textit{Apache} un utilisateur et donner cet utilisateur les droits ncessaires une bonne utilisateur de \textit{Apache}. La premire consiste crer cet utilisateur (voir figure~\ref{user_creation_with_windows_nt}) puis lui confrer les bons droits. - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=4cm, width=10cm]{\filextel{../python_cours/image/apant0}} \\ \hline - \includegraphics[height=6cm, width=10cm]{\filextel{../python_cours/image/apant1}} - \\ \hline - \end{tabular}\end{center} - \caption{Pour ajouter un utilisateur, il faut aller - dans le \textit{Panneau de Contrle}, choisir \textit{Outils d'administration} puis - choisir \textit{Computer Management}. La seconde image indique comment ajouter un utilisateur en cliquant - avec le bouton droit sur le rpertoire \textit{Users} ou \textit{Utilisateurs}.} - \label{user_creation_with_windows_nt} - \end{figure} - -L'tape suivante consiste donner cet utilisateur nouvellement cr les droits ncessaires la modification des rpertoires d'\textit{Apache} (voir la figure~\ref{user_creation_with_windows_nt_folder}). L'tape suivante est l'attribution de droits administrateur l'utiliseur \codes{apache} (figure~\ref{user_creation_with_windows_nt_folder_rights}). La dernire tape est la configuration du service \textit{Apache} ce qu'illustre la figure~\ref{user_creation_with_windows_nt_folder_service}. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|c|}\hline - \includegraphics[height=6cm, width=4.5cm]{\filextel{../python_cours/image/apant2}} & - \includegraphics[height=6cm, width=4.5cm]{\filextel{../python_cours/image/apant3}} - \\ \hline - \end{tabular}\end{center} - \caption{L'utilisateur \codescaption{apache} cr par les tapes - illustres la figure~\ref{user_creation_with_windows_nt} doit avoir les droits - d'accs en lecture et excution pour le rpertoire d'installation d'\textit{Apache}. Il doit aussi avoir les - droits en criture pour le rpertoire \textit{logs}. Si \textit{Apache} utilise des extensions comme \textit{SVN} ou - des rpertoires de pages ou de scripts situs ailleurs, il faudra galement ajouter l'utilisateur - \codescaption{apache} la liste - des utilisateurs autoriss lire ou crire ces emplacements.} - \label{user_creation_with_windows_nt_folder} - \end{figure} - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=10cm, width=18cm]{\filextel{../python_cours/image/apant4}} - \\ \hline - \end{tabular}\end{center} - \caption{Il faut donner l'utilisateur \codescaption{apache} des droits d'administrateurs. Il faut pour cela aller dans le - \textit{Panneau de configuration}, sur \textit{Outils d'Administration} puis sur \textit{Local Secruity Policy}. - On termine par l'ajout de l'utilisateur \codescaption{apache} - au droit \textit{Act a part of the operating system}. } - \label{user_creation_with_windows_nt_folder_rights} - \end{figure} - - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=10cm, width=18cm]{\filextel{../python_cours/image/apant5}} - \\ \hline - \end{tabular}\end{center} - \caption{Il faut maintenant prciser au service - \textit{Apache} qu'il doit utiliser les droits de l'utilisateur \codescaption{apache}. - Il faudra redmarrer pour prendre en compte les modifications.} - \label{user_creation_with_windows_nt_folder_service} - \end{figure} - - -\subsubsection{Sans ODBC} \label{conexxion_directe_mysql} - -Il arrive que sur certains systmes, la configuration d'\textit{Apache} en tant que service soit difficile pour un non expert bien que cela soit rendu ncessaire par l'utilisation de pilotes ODBC dans de scripts CGI crits en \python. Il existe une alternative qui est de se connecter directement au serveur \textit{MySQL}. Il faut pour cela utiliser le module \codes{MySQLdb}\footnote{\httpstyle{http://sourceforge.net/projects/mysql-python}}.\indexmoduleext{MySQLdb} Le code permettant de lancer une requte diffre peu de celui utiliser pour une connexion ODBC comme le montre les deux exemples suivant. -% -\begin{center}\begin{tabular}{cc} -\begin{minipage}{8cm} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import odbc -cx = odbc.odbc("mysqlperso") - -cur = cx.cursor() -cur.execute ("SELECT * from ELEVE") -for row in cur.fetchall () : - print row -cur.close () - -\end{verbatimx} -\end{minipage} -& -\begin{minipage}{8cm} -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import MySQLdb -cx = MySQLdb.connect('localhost','root', \ - 'admin', 'datatest') -cur = cx.cursor() -cur.execute ("select * from ELEVE" ) -for row in cur.fetchall() : - print row -cur.close() -cx.close() -\end{verbatimx} -\end{minipage} -\end{tabular}\end{center} -% -Il faut toutefois penser fermer la connexion vers le serveur \textit{MySQL}, tche que le pilote ODBC gre seul. Le serveur \textit{MySQL} ne peut supporter trop de connexions ouvertes au mme moment\footnote{Ceci dpend de la configuration du serveur et de la puissance de l'ordinateur sur lequel il est install.}. - -Si le serveur de base de donnes est diffrent de \textit{MySQL}, il suffit de taper \textit{python + } dans un moteur de recherche pour trouver le module qui permet de communiquer avec ce serveur. Par exemple, pour \textit{Oracle}, on trouve le module \codes{cx-oracle}\footnote{\httpstyle{http://cx-oracle.sourceforge.net/}}.\indexmoduleext{cx-oracle} La syntaxe permettant de lancer une requte est sensiblement la mme. Un serveur droge cette rgle, il s'agit de \textit{MSSQL Server} de \textit{Microsoft} qui utilise le module \codes{win32com}\footnote{\httpstyle{http://python.net/crew/mhammond/win32/Downloads.html}}\indexmoduleext{win32com} dont voici un exemple d'utilisation. -% -\indexexemples{\textit{SQL}}{} -\begin{verbatimx} -import win32com.client -connexion = win32com.client.gencache.EnsureDispatch('ADODB.Connection') -connexion.Open("Provider='SQLOLEDB';Data Source='localhost';Initial Catalog='datatest';User ID='root';Password='admin';") -recordset = connexion.Execute('select * from client')[0] -while not recordset.EOF: - for i in recordset.Fields : print i, - print "
    \n" - recordset.MoveNext() -connexion.Close() -\end{verbatimx} -% -ODBC fournit une interface de connexion qui ne change pas quelque soit le serveur SQL utilis, c'est tout l'avantage d'un tel systme. Accder directement au serveur est plus rapide mais plus contraignant si la base de donnes est transfre sur un serveur diffrent. C'est pourquoi il est recommand de regrouper le code qui a trait aux bases de donnes. Ceci peut tre fait manuellement ou en utilisant un module qui propose une unique interface quelque soit le serveur de base de donnes utilis. - -\codes{SQLObject}\footnote{\httpstyle{http://www.sqlobject.org/}}\indexmoduleext{SQLObject} s'appuie sur les classes pour reprsenter les tables d'une base de donnes. Une table est considre comme une liste d'instances d'un mme objet dont les attributs sont stocks dans la table. Cette conception objet remplace en partie le langage SQL et est bien adapt aux bases de donnes relationnelles\indexfr{base de donnes relationnelle} qui permettent de lier des attributs de plusieurs tables. - -\section{Modules divers} - -\subsection{PDF} - -De mme que \pythons propose des outils pour crire et lire des fichiers \textit{zip}, il existe des modules permettant de constuire des fichiers \textit{pdf}\indexfr{pdf} et d'extraire des informations depuis des documents de ce format. Le module \codes{reportLab}\footnote{\httpstyle{http://www.reportlab.org/rl\_toolkit.html}}\indexmoduleext{reportLab} permet de construire automatique des fichiers au format \textit{pdf}. Ceci vite par exemple l'utilisation d'application intermdiaire comme \textit{Latex} par exemple. \indexfrr{pdf}{\codes{reportLab}}\indexfrr{pdf}{crire} - -Un autre module permet d'extraire des informations textuelles depuis un fichier \textit{pdf} condition que celui-ci ne soit pas crypt~: \codes{pdftools}\footnote{\httpstyle{http://www.boddie.org.uk/david/Projects/Python/pdftools/}}\indexmoduleext{pdftools}. Le programme suivant permet d'extraire tout le texte d'un document \textit{pdf}. \indexfrr{pdf}{lire}\indexfrr{pdf}{\codes{pdftools}}\indexfrr{fichier}{pdf} -% -\inputcode{../python_cours/programme/extrpdf.py}{extraction du texte d'un fichier \textit{pdf}} - -Le module \codes{pyPDF}\footnote{\httpstyle{http://pybrary.net/pyPdf/}} propose des fonctionnalits quivalentes. Le module le plus rcemment mis jour est souvent le meilleur choix. - -\subsection{Tesseract} \indexoutil{Tesseract} - -\textit{Tesseract} est un outil gratuit de reconnaissance de l'criture imprime (OCR)\indexfr{OCR} qui est capable de transcrire le texte depuis une page imprime puis scanne. Il s'utilise depuis le module \codes{pytesser}\footnote{\httpstyle{http://code.google.com/p/pytesser/}}\indexmoduleext{pytesser} Il fonctionne assez simplement et il suffit d'excuter le programme \codes{pytesser.py} pour le faire fonctionner. - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{Graphisme} \indexfr{graphisme} - -\subsection{GNUPlot} \indexoutil{GNUPlot} - -\textit{GNUPlot}\footnote{\httpstyle{http://www.gnuplot.info/}} est un logiciel permettant de tracer des graphes. Il a son propre langage de programmation et dispose d'une large panoplie de types de graphismes.\indexfr{graphe} Il existe la fois sous \textit{Windows} et \textit{Linux}. Le programme suivant construit un script GNUPlot et l'excute de faon construire automatiquement l'image du graphique. -% -\inputcode{../python_cours/programme/graphplot.py}{graphiques avec GNUPlot} - -\subsection{MatPlotLib} \indexoutil{MatPlotLib}\indexmoduleext{matplotlib} - -Ce module imite la syntaxe de \textit{Matlab} en ce qui concerne la cration de graphe. Il propose les mmes fonctionnalits. Le programme suivant montre comment tracer une srie financire. -% -\inputcode{../python_cours_exemple/programme/graphohlc.py}{graphiques avec MatPlotLib} - - - - - -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ -%------------------------------------------------------------------------------------------------------------------------------------ - -\section{Apache : serveur} \indexoutil{Apache} \indexoutilz{Apache}{installation} \label{apache_paragraphe_section} \label{apache_installation_par} - -Les paragraphes qui suivent dcrivent l'installation et la configuration du serveur \textit{Apache}. Celui est utilis par des applications comme\textit{SVN}, \textit{MoinMoin} ou tout simplement, il offre la possibilit d'crire des applications Internet comme des script CGI en langage \python. Il est parfois plus simple d'utiliser l'application \textit{EasyPHP}\footnote{\httpstyle{http://www.easyphp.org/}}\indexoutil{EasyPHP} qui en simplifie l'installation surtout s'il faut installer ensuite le serveur de base de donnes \textit{MySQL}. La suite vient avec l'installation d'\textit{Apache} version 2.2\footnote{Lors de l'criture du livre, la version tait 2.2.8 et tlchargeable l'adresse \httpstyle{http://httpd.apache.org/}.} - -\subsection{Installation} - - -\indexoutil{Apache} -L'installation commence par un premier cran qu'il faut remplir en suivant les instructions de la figure~\ref{fig_aoache_inst}. Pour vrifier que l'installation a fonctionn, il suffit d'ouvrir un navigateur comme \textit{Firefox}. Aprs avoir rentr \httpstyle{http://localhost/} dans la barre d'adresse, le message \textit{It works~!} apparat si \textit{Apache} fonctionne. - - \begin{figure}[ht] - \begin{center}\begin{tabular}{|c|}\hline - \includegraphics[height=6cm, width=7cm]{\filextel{../python_cours/image/apachein}} - \\ \hline - \end{tabular}\end{center} - \caption{Installation de \textit{Apache}, \codescaption{DomainName} est un nom de domaine, dans un rseau local, - cela correspond l'adresse IP de l'ordinateur. (crire \codescaption{ipconfig \; /all} en ligne de commande - pour l'obtenir. \codescaption{ServerName} est le nom du serveur, le plus souvent \codescaption{localhost} qui dsigne - l'ordinateur local. L'adresse email peut tre n'importe quel email.} - \label{fig_aoache_inst} - \end{figure} - -\begin{xremark}{changement de port pour \textit{Apache}} -Il est possible de le port par dfaut 80 soit dj utilis par d'autres services. Le port se rsume un numro, un emplacement, o le serveur \textit{Apache} va couter et envoyer des informations. Toute application qui veut envoyer des informations \textit{Apache} doit spcifier le nom de la machine sur laquelle est installe \textit{Apache} ainsi que le port sur lequel il coute. Si deux serveurs coutent le port~80, lequel va recevoir un message, il ne sera pas non plus possible de les distinguer puisqu'ils coutent la mme entre. Pour le changer, il faut aller dans le fichier \codes{httpd.conf} et changer la ligne \codes{Listen\;80} par~: \indexfr{port}\indexoutilz{Apache}{port} -\begin{verbatimx} -Listen 81 -\end{verbatimx} -Ensuite, dans l'exporateur internet, il faut prciser ce port qui n'est plus le port par dfaut 80 et entrer l'adresse suivante~: \httpstyle{http://localhost:81/} ou ajouter \codes{http://nom\_de\_machine:81} si le serveur \textit{Apache} est appele depuis une autre machine du rseau. -\end{xremark} - - -\subsection{Configuration de \textit{Apache} pour \textit{MoinMoin}} \label{configuration_apache_moinmoin} - - -Il reste configurer \textit{Apache} pour voluer de paire avec \textit{SVN}. Il y a quatre tapes~: -\begin{enumerate} -\item Copier les fichiers \codes{mod\_dav\_svn.so} et \codes{mod\_authz\_svn.so} depuis le rpertoire d'installation de \textit{SVN} (sous-rpertoire \textit{bin}) dans le rpertoire d'installation de \codes{Apache} (sous-rpertoire \textit{module}). -\item Ouvrir le fichier de configuration de \textit{Apache} depuis le menu \textit{Dmarrer} de \textit{Windows} et insrer les lignes suivantes~: -\indexexemples{\textit{Apache}}{} -\begin{verbatimx} -LoadModule dav_module modules/mod_dav.so -LoadModule dav_svn_module modules/mod_dav_svn.so -LoadModule authz_svn_module modules/mod_authz_svn.so - - - DAV svn - SVNListParentPath on - SVNParentPath "c:/svnrepository/" - SVNPathAuthz on - #AuthzSVNAccessFile "C:/Program Files/Apache Software Foundation/Apache2.2/bin/apachesvnauth - AuthName "Subversion Repositories" - AuthType Basic - AuthBasicProvider file - AuthUserFile "C:/Program Files/Apache Software Foundation/Apache2.2/bin/apachesvnpasswd" - require valid-user - -\end{verbatimx} -Il faut remplacer \codes{c:/svnrepository/} par le rpertoire du repository cr et \codes{C:/Program\; Files/Apache\; Software Foundation/Apache2.2} par le rpertoire d'installation de \textit{Apache}. -\item Il reste insrer des utilisateurs authoriss utiliser \codes{SVN}. Pour cela il faut ouvrir une fentre de commande \textit{Windows}~: -\begin{verbatimx} -cd C:\Program Files\Apache Software Foundation\Apache2.2\bin -htpasswd.exe -c apachesvnpasswd utilisateur -\end{verbatimx} -Il vous sera demand de rentrer un mot de passe pour chaque utilisateur. -\item Il reste redmarrer le serveur \codes{Apache} afin qu'il prenne en compte ces modifications. Ce peut tre fait depuis le sous-menu \textit{Apache} du menu \textit{Dmarrer / Tous les programmes}. -\end{enumerate} -% -Pour vrifier que cela fonctionne, il faut ouvrir un navigateur et crire \httpstyle{http://localhost/svn/}. L'explorateur vous demandera de vous identifier, il suffira de rentrer un des utilisateurs et son mot de passe dfinis en tape~3. - -\begin{xremark}{problme de chargement du module \codes{mod\_dav\_svn.so}} -Il arrive parfois que le serveur n'arrive pas redmarrer aprs avoir modifi le fichier \codes{httpd.conf} car le module \codes{mod\_dav\_svn.so} ne peut tre charg\footnote{Cette information est prsente dans le fichier \codesnote{logs/error.log} dans le rpertoire d'installation d'\textit{Apache}.}. Cette erreur peut survenir si la version de \textit{Windows} n'est pas rcente o sur laquelle n'a pas t installe la dernire ou les dernires mises jour de \textit{Windows}. -\end{xremark} - -D'autres prcisions concernant la configuration d'\textit{Apache} sont dcrites aux paragraphes~\ref{configuration_apache_sql_plus} et~\ref{configuration_apache_sql_plus}. \indexoutilz{Apache}{installation} - - -La configuration d'\textit{Apache} fait intervenir deux lments. Le premier est la dfinition d'alias.\indexoutilz{Apache}{alias} Il s'agit de dire \textit{Apache} que tous les adresses URL contenant la mme racine (ici \httpstyle{http://localhost/mywiki}) font partie du \textit{Wiki} et contiennent des scripts \python. Il faut ajouter les lignes suivantes dans le fichier \codes{httpd.conf}. -% -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} -ScriptAlias /mywiki "C:/Moin/mywiki/moin.cgi" -Alias /moin_static163 "C:/Python25/share/moin/htdocs" -\end{verbatimx} -% -La seconde tape est l'attribution de droits au rpertoire contenant plusieurs rpertoires essentiels au \codes{Wiki} mais qui sont situs en dehors du chemin \codes{DocumentRoot}. Toujours dans le fichier \codes{httpd.conf}, il faut ajouter les lignes en fin de fichier~: -\indexexemples{\textit{MoinMoin}}{} -\begin{verbatimx} - - Order deny,allow - Allow from all - - - Options FollowSymLinks - AllowOverride None - Order deny,allow - Allow from all - -\end{verbatimx} -% -Il ne faut pas oublier de redmarrer le serveur pour que ces modifications soient bien prises en compte. Avec cette configuration, il suffit que chaque script \pythons commence par une ligne indiquant l'emplacement de l'interprteur \python. -\begin{verbatimx} -#!c:/python25/python.exe -\end{verbatimx} -Ou sous Linux : -\begin{verbatimx} -#!/usr/bin/python -\end{verbatimx} -Cette premire ligne est appele par \textit{Apache} un \textit{shebang}.\indexfr{shebang} Si un script CGI doit tre excut sur des serverus \textit{Apache} installs sur deux systmes d'exploitation diffrent, cette ligne empche le passage de l'un l'autre. \textit{Apache} peut tre configurer de faon ce qu'il sache automatiquement quoi faire lors de l'excution d'un script CGI d'extension \codes{.py}. - -\begin{verbatimx} -ScriptInterpreterSource registry - # il faut galement une section - AllowOverride None # comme celle-ci dfinie - Options ExecCGI # pour le rpertoire contenant - Order allow,deny # le script CGI - Allow from all # - -AddType application/x-httpd-py .py -AddHandler cgi-script .py -Action application/x-httpd-py "C:/python25/python.exe" -\end{verbatimx} - -\begin{xremark}{\codes{Alias}, \textit{Apache} et \textit{MoinMoin}} -Les alias sous \textit{Apache} permettent de remplacer une chemin donn par un autre dans tous les hyperliens. Ici \codes{/moin\_static163/} sera remplac par \codes{C:/Python25/share/moin/htdocs/}. Un dernier dtail, pour une version ultrieure de \textit{MoinMoin}, il est possible que l'alias dfini pour \codes{moin\_static163} diffre, 163 est en effet la liste des chiffres du numro de version. Pour en tre sr, il suffit d'afficher le \textit{source} d'une page du \codes{Wiki} depuis l'navigateur. Toutefois, il est possible de modifier ce chemin depuis \textit{MoinMoin}. -\end{xremark} - -\begin{xremark}{\textit{Apache}, comprendre une erreur} -Dans le rpertoire d'installation de \textit{Apache}, on trouve le sous-rpertoire \codes{logs} et le fichier \codes{error.log} dans lequel figurent des informations concernant l'excution du serveur. Si une page HTML ou un script ne s'excute pas comme il le devrait, un message d'erreur est insr dans ce fichier si l'erreur se situe au niveau de \textit{Apache}. Les exceptions \pythons sont galement prsentes dans ce fichier lorsqu'un script CGI\footnote{Le rle des CGI est brivement expliqu au paragraphe~\ref{cgi_definition}.} provoque une erreur d'excution. -\end{xremark} - -D'autres remarques concernant des problmes ventuels survenant lors de l'installation d'\textit{Apache} sont dcrites au paragraphe~\ref{configuration_apache_sql_plus}. \indexoutilz{Apache}{installation} - -\subsection{Pour aller plus loin} - -Pour savoir quels ports sont disponibles lors de l'installation d'\textit{Apache} sous \textit{Windows}. Il suffit d'excuter la commande~: - -\begin{verbatimx} -netstat -ao -\end{verbatimx} - -Il est possible de configurer un second serveur \textit{Apache}, c'est--dire un nouveau service, un second port, un second fichier de configuration. - -\begin{verbatimx} -httpd -k uninstall -n ApacheSecond # on dsinstalle le service s'il existait -httpd -f "new_conf.conf" -n ApacheSecond -k install # on installe nouveau le service -httpd -n ApacheSecond -k start # on dmarre Apache -\end{verbatimx} - -Cette modification est parfois ncessaire car pour installer un serveur SVN, il existe deux solutions~: -\begin{enumerate} -\item La solution prsente prcdemment, qu'il est possible de simplifier en utilisant la distribution \textit{CollabNet}\footnote{\httpstyle{http://www.collab.net/}, cette distribution n'aime pas trop les login avec un symbol "-".} qui installe tout automatiquement except qu'il faut faire attention si un autre serveur \textit{Apache} existe (cette distribution utilise Python 2.5 et il vaut mieux ne pas mlanger les diffrentes versions de Python.) -\item Lancer le serveur SVN (svnserve.exe) disponible lors de l'installation de SVN. -\end{enumerate} - -Lors de l'installation du serveur \textit{Apache}, il est possible de rencontrer cette erreur~: - -\begin{verbatimx} -(OS 10048)Only one usage of each socket address (protocol/network address/port) is normally permitted. : make_sock: could not bind to address 0.0.0.0:8084 -no listening sockets available, shutting down -Unable to open logs -\end{verbatimx} - -J'ai rencontre cette erreur alors le fichier de configuration contenait deux fois l'instruction \codes{Listen} pour deux ports diffrents. Autre dtail, il est possible de restreindre l'accs au serveur en crant une rgle au niveau de Firewall de Windows. - - - - - -\subsection{Configuration pour des applications CGI} - - -La configuration du serveur \textit{Apache} pour l'excution de script CGI en langage \pythons passe toujours par la prcision des bons droits pour le rpertoire contenant le langage \pythons et celui contenant le script CGI. - -\begin{verbatimx} - - AllowOverride None - Options ExecCGI - Order allow,deny - Allow from all - - - AllowOverride None - Options FollowSymLinks ExecCGI - Order allow,deny - Allow from all - -\end{verbatimx} - -Il faut prciser ensuite que l'extension \textit{.py} est celle d'un script CGI et qu'il doit s'excuter avec l'interprteur \python~: - -\begin{verbatimx} - - TypesConfig conf/mime.types - AddType application/x-httpd-py .py - AddHandler cgi-script .py - -Action application/x-httpd-py "C:/python25/python.exe" -\end{verbatimx} - -Il ne reste plus qu' donner un alias au rpertoire contenant le script CGI~: - -\begin{verbatimx} -ScriptAlias /py/ "C:/script_cgi_python/" -\end{verbatimx} - -Par exemple, le fichier suivant nomm \codes{script.py} est plac dans le rpertoire prcdent. - -\begin{verbatimx} -header = """Content-type: text/html - - - - - - -""" - -footer = """""" - -print header -print "Script CGI
    \n" -print footer -\end{verbatimx} - -Pour l'excuter via un navigateur, il suffit alors de taper l'adresse~: - -\begin{verbatimx} -http://localhost:80/py/script.py -\end{verbatimx} - - - -\firstpassagedo{ - \begin{thebibliography}{99} - \input{python_cours_biblio.tex} - \end{thebibliography} -} - -\input{../../common/livre_table_end.tex}% -\input{../../common/livre_end.tex}% diff --git a/_todo/conseil_ecrire_programme.tex b/_todo/conseil_ecrire_programme.tex deleted file mode 100644 index 2ebc79b6..00000000 --- a/_todo/conseil_ecrire_programme.tex +++ /dev/null @@ -1,88 +0,0 @@ -%!TEX encoding = IsoLatin -\input{../../common/paper_begin.tex}% - - -\firstpassagedo{ -\title{Ecrire un programme plusieurs} -\author{Xavier Dupr \\ \httpstyle{http://www.xavierdupre.fr/}} -\maketitle -\begin{abstract} -\noindent Deux pages et quelques ides pour travailler plusieurs sur le mme projet de programmation. -\end{abstract} -} - - -\section{Trois conseils pour crire un programme} - -\subsection{Des petites fonctions} - -Pour plusieurs raisons~: -\begin{enumerate} -\item Il est plus facile de corriger un programme qui est constitu de petites fonctions plutt que de quelques grandes. Chaque fonction peut tre vrifie sparment. -\item Il est plus facile de rutiliser des petites fonctions. -\item Il est plus facile de rpartir le travail sur plusieurs personnes. -\end{enumerate} - -\begin{xremark}{variables globales} -Il vaut mieux viter les variables globales qui sont considres que comme des paramtres cachs. -\end{xremark} - - - -\subsection{Sparer les calculs, le chargement des donnes, l'interface graphique} - -Pour plusieurs raisons~: -\begin{enumerate} -\item Il est plus facile de vrifier un calcul s'il est dans une fonction indpendante plutt que cach dans le code d'une interface graphique. -\item C'est facile de faire un calcul une fois lorsqu'un utilisateur appuie sur un bouton, si on veut faire ce calcul cent fois, on ne peut pas lui demander d'appuyer cent fois sur le mme bouton. -\item Les calculs ou le chargement des donnes peuvent tre utiliss dans d'autres programmes. -\end{enumerate} - -\subsection{Utiliser des fonctions de tests} - -Ces fonctions peuvent tre excutes au dbut du programme pour vrifier que certaines parties du programme fonctionnent toujours mme aprs les avoir modifies. - -L'exemple suivant considre une fonction qui doit retourner une somme relle mme si les lments de la liste sont entiers. On crit la fonction qui vrifie cela. - -\begin{verbatimx} -def somme_double (liste) : - return 1.0 * sum(liste) - -def test_somme_double () : - y = somme_double([ 1 ]) / 2 - if y == 0 : raise Exception ("valeur > 0 attendue") - -if __name__ == "__main__" : - test_somme_double() -\end{verbatimx} - -Si plus tard, quelqu'un modifie la fonction \codes{somme\_double} en enlevant la multiplication parce qu'il considre cela inutile. La fonction de test provoquera une erreur. Elle est l pour rappeler que la fonction a t programme pour retourner un nombre rel et que quiconque l'utilise s'attend ce qu'elle retourne ce type de rsultat. - -\begin{verbatimx} -Traceback (most recent call last): - File "conseil.py", line 10, in - test_somme_double() - File "conseil.py", line 7, in test_somme_double - if y == 0 : raise Exception ("valeur > 0 attendue") -Exception: valeur > 0 attendue -\end{verbatimx} - -\section{Trucs et astuces} - - -\subsection{Partager du code} - -Il existe aujourd'hui des solutions qui permettent d'viter les envois de programme par email. Des outil comme \textit{DropBox}, \textit{SkyDrive}, \textit{GoogleDrive} permettent de partager un rpertoire. Un mme rpertoire peut tre partag sur plusieurs ordinateurs et plusieurs personnes. Une modification (y compris une suppression) sur l'une des rpliques sera propage sur tous les ordinateurs ds qu'ils sont connects Internet. - -Il est possible de coupler cette solution avec \textit{SVN} ou \textit{TortoiseSVN} qui sont des logiciels de suivis de source. On garde la fois la dernire version et l'historique des modifications\footnote{\httpstyle{http://mlevit.wordpress.com/2009/11/18/how-to-use-subversion-dropbox-to-create-an-effective-work-managementbackup-system/}}. - - -\subsection{Moteurs de recherche} - -Lorsqu'on ne comprend un message d'erreur, il est souvent utile de recopier le texte dans un moteur de recherche (Google, Bing, ...). Il est trs rare de ne pas russir trouver d'indices. - - - - - -\input{../../common/paper_end.tex}% diff --git a/_todo/exemple.tex b/_todo/exemple.tex deleted file mode 100644 index 89b8d48e..00000000 --- a/_todo/exemple.tex +++ /dev/null @@ -1,32 +0,0 @@ -\input{../../common/livre_begin.tex}% -\firstpassagedo{\input{python_cours_titre.tex}} -\input{../../common/livre_table_begin.tex}% -%\firstpassagedo{\input{python_cours_chapter.tex}} - - - - - - -%------------------------------------------------------------------------------------------------------------- -\chapter{Introduction} -%------------------------------------------------------------------------------------------------------------- - - - - - - - - - -\firstpassagedo{ - \begin{thebibliography}{99} - \input{python_cours_biblio.tex} - \end{thebibliography} -} - - - -\input{../../common/livre_table_end.tex}% -\input{../../common/livre_end.tex}% diff --git a/_todo/image/after.bmp b/_todo/image/after.bmp deleted file mode 100644 index d84bd638..00000000 Binary files a/_todo/image/after.bmp and /dev/null differ diff --git a/_todo/image/after.png b/_todo/image/after.png deleted file mode 100644 index 107d80c0..00000000 Binary files a/_todo/image/after.png and /dev/null differ diff --git a/_todo/image/apachein.PNG b/_todo/image/apachein.PNG deleted file mode 100644 index 2f2d7828..00000000 Binary files a/_todo/image/apachein.PNG and /dev/null differ diff --git a/_todo/image/apant0.png b/_todo/image/apant0.png deleted file mode 100644 index 911e9ee5..00000000 Binary files a/_todo/image/apant0.png and /dev/null differ diff --git a/_todo/image/apant1.png b/_todo/image/apant1.png deleted file mode 100644 index 695e704b..00000000 Binary files a/_todo/image/apant1.png and /dev/null differ diff --git a/_todo/image/apant2.png b/_todo/image/apant2.png deleted file mode 100644 index 608e1fbb..00000000 Binary files a/_todo/image/apant2.png and /dev/null differ diff --git a/_todo/image/apant3.png b/_todo/image/apant3.png deleted file mode 100644 index 45cbb739..00000000 Binary files a/_todo/image/apant3.png and /dev/null differ diff --git a/_todo/image/apant4.PNG b/_todo/image/apant4.PNG deleted file mode 100644 index 54a88b7c..00000000 Binary files a/_todo/image/apant4.PNG and /dev/null differ diff --git a/_todo/image/apant5.PNG b/_todo/image/apant5.PNG deleted file mode 100644 index a315faa2..00000000 Binary files a/_todo/image/apant5.PNG and /dev/null differ diff --git a/_todo/image/arbo.bmp b/_todo/image/arbo.bmp deleted file mode 100644 index e5ef94a9..00000000 Binary files a/_todo/image/arbo.bmp and /dev/null differ diff --git a/_todo/image/arbo.png b/_todo/image/arbo.png deleted file mode 100644 index fcadfafb..00000000 Binary files a/_todo/image/arbo.png and /dev/null differ diff --git a/_todo/image/bbette.bmp b/_todo/image/bbette.bmp deleted file mode 100644 index 7c071f86..00000000 Binary files a/_todo/image/bbette.bmp and /dev/null differ diff --git a/_todo/image/bbette.png b/_todo/image/bbette.png deleted file mode 100644 index 9527eb14..00000000 Binary files a/_todo/image/bbette.png and /dev/null differ diff --git a/_todo/image/bbette2.png b/_todo/image/bbette2.png deleted file mode 100644 index 4c0a3f1e..00000000 Binary files a/_todo/image/bbette2.png and /dev/null differ diff --git a/_todo/image/bind.bmp b/_todo/image/bind.bmp deleted file mode 100644 index b2092621..00000000 Binary files a/_todo/image/bind.bmp and /dev/null differ diff --git a/_todo/image/bind.png b/_todo/image/bind.png deleted file mode 100644 index dea0117e..00000000 Binary files a/_todo/image/bind.png and /dev/null differ diff --git a/_todo/image/boost.png b/_todo/image/boost.png deleted file mode 100644 index 0690a111..00000000 Binary files a/_todo/image/boost.png and /dev/null differ diff --git a/_todo/image/boostp.png b/_todo/image/boostp.png deleted file mode 100644 index 78205102..00000000 Binary files a/_todo/image/boostp.png and /dev/null differ diff --git a/_todo/image/bouton.bmp b/_todo/image/bouton.bmp deleted file mode 100644 index 8778ec6d..00000000 Binary files a/_todo/image/bouton.bmp and /dev/null differ diff --git a/_todo/image/bouton.png b/_todo/image/bouton.png deleted file mode 100644 index 12ceb1c6..00000000 Binary files a/_todo/image/bouton.png and /dev/null differ diff --git a/_todo/image/bouton2.bmp b/_todo/image/bouton2.bmp deleted file mode 100644 index 210bfc4f..00000000 Binary files a/_todo/image/bouton2.bmp and /dev/null differ diff --git a/_todo/image/bouton2.png b/_todo/image/bouton2.png deleted file mode 100644 index f3b5dd54..00000000 Binary files a/_todo/image/bouton2.png and /dev/null differ diff --git a/_todo/image/bouton3.bmp b/_todo/image/bouton3.bmp deleted file mode 100644 index a03b3f7a..00000000 Binary files a/_todo/image/bouton3.bmp and /dev/null differ diff --git a/_todo/image/bouton3.png b/_todo/image/bouton3.png deleted file mode 100644 index e5416e48..00000000 Binary files a/_todo/image/bouton3.png and /dev/null differ diff --git a/_todo/image/can.bmp b/_todo/image/can.bmp deleted file mode 100644 index 6cfc5fad..00000000 Binary files a/_todo/image/can.bmp and /dev/null differ diff --git a/_todo/image/can.png b/_todo/image/can.png deleted file mode 100644 index 2ffe0995..00000000 Binary files a/_todo/image/can.png and /dev/null differ diff --git a/_todo/image/check.bmp b/_todo/image/check.bmp deleted file mode 100644 index dea1c064..00000000 Binary files a/_todo/image/check.bmp and /dev/null differ diff --git a/_todo/image/check.png b/_todo/image/check.png deleted file mode 100644 index 0abe4031..00000000 Binary files a/_todo/image/check.png and /dev/null differ diff --git a/_todo/image/check2.bmp b/_todo/image/check2.bmp deleted file mode 100644 index 98a04036..00000000 Binary files a/_todo/image/check2.bmp and /dev/null differ diff --git a/_todo/image/check2.png b/_todo/image/check2.png deleted file mode 100644 index 4acbb92d..00000000 Binary files a/_todo/image/check2.png and /dev/null differ diff --git a/_todo/image/cmds.PNG b/_todo/image/cmds.PNG deleted file mode 100644 index 065aeece..00000000 Binary files a/_todo/image/cmds.PNG and /dev/null differ diff --git a/_todo/image/cmds26.png b/_todo/image/cmds26.png deleted file mode 100644 index fc9dfa41..00000000 Binary files a/_todo/image/cmds26.png and /dev/null differ diff --git a/_todo/image/combo1.png b/_todo/image/combo1.png deleted file mode 100644 index 24e5b405..00000000 Binary files a/_todo/image/combo1.png and /dev/null differ diff --git a/_todo/image/combo2.png b/_todo/image/combo2.png deleted file mode 100644 index 468b7de1..00000000 Binary files a/_todo/image/combo2.png and /dev/null differ diff --git a/_todo/image/comm1.bmp b/_todo/image/comm1.bmp deleted file mode 100644 index a9b0af3c..00000000 Binary files a/_todo/image/comm1.bmp and /dev/null differ diff --git a/_todo/image/comm1.png b/_todo/image/comm1.png deleted file mode 100644 index cf951ab8..00000000 Binary files a/_todo/image/comm1.png and /dev/null differ diff --git a/_todo/image/comm2.bmp b/_todo/image/comm2.bmp deleted file mode 100644 index 59c1aab7..00000000 Binary files a/_todo/image/comm2.bmp and /dev/null differ diff --git a/_todo/image/comm2.png b/_todo/image/comm2.png deleted file mode 100644 index c0b06393..00000000 Binary files a/_todo/image/comm2.png and /dev/null differ diff --git a/_todo/image/config.bmp b/_todo/image/config.bmp deleted file mode 100644 index b0041500..00000000 Binary files a/_todo/image/config.bmp and /dev/null differ diff --git a/_todo/image/config.png b/_todo/image/config.png deleted file mode 100644 index 248a3c0e..00000000 Binary files a/_todo/image/config.png and /dev/null differ diff --git a/_todo/image/entree.png b/_todo/image/entree.png deleted file mode 100644 index 568c89e2..00000000 Binary files a/_todo/image/entree.png and /dev/null differ diff --git a/_todo/image/essai.bmp b/_todo/image/essai.bmp deleted file mode 100644 index 3ea10074..00000000 Binary files a/_todo/image/essai.bmp and /dev/null differ diff --git a/_todo/image/essai.png b/_todo/image/essai.png deleted file mode 100644 index 8073b631..00000000 Binary files a/_todo/image/essai.png and /dev/null differ diff --git a/_todo/image/fenpers.png b/_todo/image/fenpers.png deleted file mode 100644 index afbf42c6..00000000 Binary files a/_todo/image/fenpers.png and /dev/null differ diff --git a/_todo/image/focus.png b/_todo/image/focus.png deleted file mode 100644 index acc86840..00000000 Binary files a/_todo/image/focus.png and /dev/null differ diff --git a/_todo/image/frame.bmp b/_todo/image/frame.bmp deleted file mode 100644 index ceb61c47..00000000 Binary files a/_todo/image/frame.bmp and /dev/null differ diff --git a/_todo/image/frame.png b/_todo/image/frame.png deleted file mode 100644 index b63fe716..00000000 Binary files a/_todo/image/frame.png and /dev/null differ diff --git a/_todo/image/graphviz.png b/_todo/image/graphviz.png deleted file mode 100644 index 63b55984..00000000 Binary files a/_todo/image/graphviz.png and /dev/null differ diff --git a/_todo/image/grid1.bmp b/_todo/image/grid1.bmp deleted file mode 100644 index 5f0d3c2b..00000000 Binary files a/_todo/image/grid1.bmp and /dev/null differ diff --git a/_todo/image/grid1.png b/_todo/image/grid1.png deleted file mode 100644 index a8333e1d..00000000 Binary files a/_todo/image/grid1.png and /dev/null differ diff --git a/_todo/image/hhw.PNG b/_todo/image/hhw.PNG deleted file mode 100644 index b0ab5a96..00000000 Binary files a/_todo/image/hhw.PNG and /dev/null differ diff --git a/_todo/image/inte.bmp b/_todo/image/inte.bmp deleted file mode 100644 index f4c3fab9..00000000 Binary files a/_todo/image/inte.bmp and /dev/null differ diff --git a/_todo/image/inte.png b/_todo/image/inte.png deleted file mode 100644 index 9adfe7b1..00000000 Binary files a/_todo/image/inte.png and /dev/null differ diff --git a/_todo/image/label.png b/_todo/image/label.png deleted file mode 100644 index 5409ed56..00000000 Binary files a/_todo/image/label.png and /dev/null differ diff --git a/_todo/image/label2.png b/_todo/image/label2.png deleted file mode 100644 index 4865cd00..00000000 Binary files a/_todo/image/label2.png and /dev/null differ diff --git a/_todo/image/ligne.png b/_todo/image/ligne.png deleted file mode 100644 index 6f1011e6..00000000 Binary files a/_todo/image/ligne.png and /dev/null differ diff --git a/_todo/image/ligne26.png b/_todo/image/ligne26.png deleted file mode 100644 index 75678ecd..00000000 Binary files a/_todo/image/ligne26.png and /dev/null differ diff --git a/_todo/image/list1.bmp b/_todo/image/list1.bmp deleted file mode 100644 index 527a7f0a..00000000 Binary files a/_todo/image/list1.bmp and /dev/null differ diff --git a/_todo/image/list1.png b/_todo/image/list1.png deleted file mode 100644 index 21931929..00000000 Binary files a/_todo/image/list1.png and /dev/null differ diff --git a/_todo/image/list2.bmp b/_todo/image/list2.bmp deleted file mode 100644 index 4ca95739..00000000 Binary files a/_todo/image/list2.bmp and /dev/null differ diff --git a/_todo/image/list2.png b/_todo/image/list2.png deleted file mode 100644 index d0ee53cd..00000000 Binary files a/_todo/image/list2.png and /dev/null differ diff --git a/_todo/image/listboxs.png b/_todo/image/listboxs.png deleted file mode 100644 index dbcce8e1..00000000 Binary files a/_todo/image/listboxs.png and /dev/null differ diff --git a/_todo/image/mainloop.PNG b/_todo/image/mainloop.PNG deleted file mode 100644 index 8560b0ed..00000000 Binary files a/_todo/image/mainloop.PNG and /dev/null differ diff --git a/_todo/image/menu.bmp b/_todo/image/menu.bmp deleted file mode 100644 index 91598839..00000000 Binary files a/_todo/image/menu.bmp and /dev/null differ diff --git a/_todo/image/menu.png b/_todo/image/menu.png deleted file mode 100644 index 5ba93226..00000000 Binary files a/_todo/image/menu.png and /dev/null differ diff --git a/_todo/image/menui.ppt b/_todo/image/menui.ppt deleted file mode 100644 index 424f0bf6..00000000 Binary files a/_todo/image/menui.ppt and /dev/null differ diff --git a/_todo/image/menut.png b/_todo/image/menut.png deleted file mode 100644 index 42df2a63..00000000 Binary files a/_todo/image/menut.png and /dev/null differ diff --git a/_todo/image/mysql1.PNG b/_todo/image/mysql1.PNG deleted file mode 100644 index 89b136b5..00000000 Binary files a/_todo/image/mysql1.PNG and /dev/null differ diff --git a/_todo/image/mysql2.PNG b/_todo/image/mysql2.PNG deleted file mode 100644 index 7c54fc33..00000000 Binary files a/_todo/image/mysql2.PNG and /dev/null differ diff --git a/_todo/image/mysql3.PNG b/_todo/image/mysql3.PNG deleted file mode 100644 index ae89b16b..00000000 Binary files a/_todo/image/mysql3.PNG and /dev/null differ diff --git a/_todo/image/mysql4.PNG b/_todo/image/mysql4.PNG deleted file mode 100644 index 80dc44ed..00000000 Binary files a/_todo/image/mysql4.PNG and /dev/null differ diff --git a/_todo/image/mysql5.PNG b/_todo/image/mysql5.PNG deleted file mode 100644 index dee756e0..00000000 Binary files a/_todo/image/mysql5.PNG and /dev/null differ diff --git a/_todo/image/mysql6.PNG b/_todo/image/mysql6.PNG deleted file mode 100644 index a86fb415..00000000 Binary files a/_todo/image/mysql6.PNG and /dev/null differ diff --git a/_todo/image/mysql7.PNG b/_todo/image/mysql7.PNG deleted file mode 100644 index f19ab94a..00000000 Binary files a/_todo/image/mysql7.PNG and /dev/null differ diff --git a/_todo/image/mysql8.PNG b/_todo/image/mysql8.PNG deleted file mode 100644 index ffa5d26f..00000000 Binary files a/_todo/image/mysql8.PNG and /dev/null differ diff --git a/_todo/image/mysqlodbc.PNG b/_todo/image/mysqlodbc.PNG deleted file mode 100644 index cec4810a..00000000 Binary files a/_todo/image/mysqlodbc.PNG and /dev/null differ diff --git a/_todo/image/mysqlodbc2.PNG b/_todo/image/mysqlodbc2.PNG deleted file mode 100644 index b5aadde7..00000000 Binary files a/_todo/image/mysqlodbc2.PNG and /dev/null differ diff --git a/_todo/image/odbc.PNG b/_todo/image/odbc.PNG deleted file mode 100644 index 53d09e78..00000000 Binary files a/_todo/image/odbc.PNG and /dev/null differ diff --git a/_todo/image/pack1.bmp b/_todo/image/pack1.bmp deleted file mode 100644 index 171c4585..00000000 Binary files a/_todo/image/pack1.bmp and /dev/null differ diff --git a/_todo/image/pack1.png b/_todo/image/pack1.png deleted file mode 100644 index 2f3cc5e1..00000000 Binary files a/_todo/image/pack1.png and /dev/null differ diff --git a/_todo/image/pack2.bmp b/_todo/image/pack2.bmp deleted file mode 100644 index 37524031..00000000 Binary files a/_todo/image/pack2.bmp and /dev/null differ diff --git a/_todo/image/pack2.png b/_todo/image/pack2.png deleted file mode 100644 index 199b8a6a..00000000 Binary files a/_todo/image/pack2.png and /dev/null differ diff --git a/_todo/image/pass.bmp b/_todo/image/pass.bmp deleted file mode 100644 index 285e3112..00000000 Binary files a/_todo/image/pass.bmp and /dev/null differ diff --git a/_todo/image/pass.png b/_todo/image/pass.png deleted file mode 100644 index 552a6da8..00000000 Binary files a/_todo/image/pass.png and /dev/null differ diff --git a/_todo/image/pcmd.png b/_todo/image/pcmd.png deleted file mode 100644 index d124f2cd..00000000 Binary files a/_todo/image/pcmd.png and /dev/null differ diff --git a/_todo/image/pcmd2.png b/_todo/image/pcmd2.png deleted file mode 100644 index 92b6845d..00000000 Binary files a/_todo/image/pcmd2.png and /dev/null differ diff --git a/_todo/image/pcmd26.png b/_todo/image/pcmd26.png deleted file mode 100644 index b70406ce..00000000 Binary files a/_todo/image/pcmd26.png and /dev/null differ diff --git a/_todo/image/popt.png b/_todo/image/popt.png deleted file mode 100644 index b04522ed..00000000 Binary files a/_todo/image/popt.png and /dev/null differ diff --git a/_todo/image/profile.bmp b/_todo/image/profile.bmp deleted file mode 100644 index a1d5fe80..00000000 Binary files a/_todo/image/profile.bmp and /dev/null differ diff --git a/_todo/image/profile.png b/_todo/image/profile.png deleted file mode 100644 index 71d2c38b..00000000 Binary files a/_todo/image/profile.png and /dev/null differ diff --git a/_todo/image/pydoc_image.png b/_todo/image/pydoc_image.png deleted file mode 100644 index 587509e4..00000000 Binary files a/_todo/image/pydoc_image.png and /dev/null differ diff --git a/_todo/image/pydoch.PNG b/_todo/image/pydoch.PNG deleted file mode 100644 index a7ffae4d..00000000 Binary files a/_todo/image/pydoch.PNG and /dev/null differ diff --git a/_todo/image/pyform1.PNG b/_todo/image/pyform1.PNG deleted file mode 100644 index 76c71b94..00000000 Binary files a/_todo/image/pyform1.PNG and /dev/null differ diff --git a/_todo/image/pyscripter.PNG b/_todo/image/pyscripter.PNG deleted file mode 100644 index 5ee9e8f6..00000000 Binary files a/_todo/image/pyscripter.PNG and /dev/null differ diff --git a/_todo/image/radio.bmp b/_todo/image/radio.bmp deleted file mode 100644 index 7c3c7dc7..00000000 Binary files a/_todo/image/radio.bmp and /dev/null differ diff --git a/_todo/image/radio.png b/_todo/image/radio.png deleted file mode 100644 index af69677d..00000000 Binary files a/_todo/image/radio.png and /dev/null differ diff --git a/_todo/image/radio2.bmp b/_todo/image/radio2.bmp deleted file mode 100644 index b1be795e..00000000 Binary files a/_todo/image/radio2.bmp and /dev/null differ diff --git a/_todo/image/radio2.png b/_todo/image/radio2.png deleted file mode 100644 index 158cb0ea..00000000 Binary files a/_todo/image/radio2.png and /dev/null differ diff --git a/_todo/image/rawinput.png b/_todo/image/rawinput.png deleted file mode 100644 index b192870e..00000000 Binary files a/_todo/image/rawinput.png and /dev/null differ diff --git a/_todo/image/reper.png b/_todo/image/reper.png deleted file mode 100644 index 6a12ce79..00000000 Binary files a/_todo/image/reper.png and /dev/null differ diff --git a/_todo/image/reper26.png b/_todo/image/reper26.png deleted file mode 100644 index 4360d8cd..00000000 Binary files a/_todo/image/reper26.png and /dev/null differ diff --git a/_todo/image/runs.bmp b/_todo/image/runs.bmp deleted file mode 100644 index c0d7d978..00000000 Binary files a/_todo/image/runs.bmp and /dev/null differ diff --git a/_todo/image/runs.png b/_todo/image/runs.png deleted file mode 100644 index eb0ce663..00000000 Binary files a/_todo/image/runs.png and /dev/null differ diff --git a/_todo/image/saisie1.png b/_todo/image/saisie1.png deleted file mode 100644 index 73717f81..00000000 Binary files a/_todo/image/saisie1.png and /dev/null differ diff --git a/_todo/image/saisie2.png b/_todo/image/saisie2.png deleted file mode 100644 index b7f509de..00000000 Binary files a/_todo/image/saisie2.png and /dev/null differ diff --git a/_todo/image/scite1.png b/_todo/image/scite1.png deleted file mode 100644 index f2581291..00000000 Binary files a/_todo/image/scite1.png and /dev/null differ diff --git a/_todo/image/scite2.png b/_todo/image/scite2.png deleted file mode 100644 index e1d5d385..00000000 Binary files a/_todo/image/scite2.png and /dev/null differ diff --git a/_todo/image/scite226.png b/_todo/image/scite226.png deleted file mode 100644 index b0a84537..00000000 Binary files a/_todo/image/scite226.png and /dev/null differ diff --git a/_todo/image/seqev.png b/_todo/image/seqev.png deleted file mode 100644 index be80fbbe..00000000 Binary files a/_todo/image/seqev.png and /dev/null differ diff --git a/_todo/image/sql1.PNG b/_todo/image/sql1.PNG deleted file mode 100644 index 336e7b38..00000000 Binary files a/_todo/image/sql1.PNG and /dev/null differ diff --git a/_todo/image/svn1.png b/_todo/image/svn1.png deleted file mode 100644 index 52b3f599..00000000 Binary files a/_todo/image/svn1.png and /dev/null differ diff --git a/_todo/image/svn10a.PNG b/_todo/image/svn10a.PNG deleted file mode 100644 index 71d2c458..00000000 Binary files a/_todo/image/svn10a.PNG and /dev/null differ diff --git a/_todo/image/svn10b.PNG b/_todo/image/svn10b.PNG deleted file mode 100644 index fe79d957..00000000 Binary files a/_todo/image/svn10b.PNG and /dev/null differ diff --git a/_todo/image/svn11a.PNG b/_todo/image/svn11a.PNG deleted file mode 100644 index 58a31f1a..00000000 Binary files a/_todo/image/svn11a.PNG and /dev/null differ diff --git a/_todo/image/svn11b.PNG b/_todo/image/svn11b.PNG deleted file mode 100644 index 83a98afc..00000000 Binary files a/_todo/image/svn11b.PNG and /dev/null differ diff --git a/_todo/image/svn12_.PNG b/_todo/image/svn12_.PNG deleted file mode 100644 index b31c3e7d..00000000 Binary files a/_todo/image/svn12_.PNG and /dev/null differ diff --git a/_todo/image/svn2ex.PNG b/_todo/image/svn2ex.PNG deleted file mode 100644 index 700b53c9..00000000 Binary files a/_todo/image/svn2ex.PNG and /dev/null differ diff --git a/_todo/image/svn3r.PNG b/_todo/image/svn3r.PNG deleted file mode 100644 index d5600264..00000000 Binary files a/_todo/image/svn3r.PNG and /dev/null differ diff --git a/_todo/image/svn4f.PNG b/_todo/image/svn4f.PNG deleted file mode 100644 index 876ffc65..00000000 Binary files a/_todo/image/svn4f.PNG and /dev/null differ diff --git a/_todo/image/svn5f.PNG b/_todo/image/svn5f.PNG deleted file mode 100644 index 7a178f6d..00000000 Binary files a/_todo/image/svn5f.PNG and /dev/null differ diff --git a/_todo/image/svn61.PNG b/_todo/image/svn61.PNG deleted file mode 100644 index 2255f2f5..00000000 Binary files a/_todo/image/svn61.PNG and /dev/null differ diff --git a/_todo/image/svn72.PNG b/_todo/image/svn72.PNG deleted file mode 100644 index 65bf24c6..00000000 Binary files a/_todo/image/svn72.PNG and /dev/null differ diff --git a/_todo/image/svn8n.PNG b/_todo/image/svn8n.PNG deleted file mode 100644 index 0b5b1fe6..00000000 Binary files a/_todo/image/svn8n.PNG and /dev/null differ diff --git a/_todo/image/svn8nn.PNG b/_todo/image/svn8nn.PNG deleted file mode 100644 index 93259505..00000000 Binary files a/_todo/image/svn8nn.PNG and /dev/null differ diff --git a/_todo/image/svn9a.PNG b/_todo/image/svn9a.PNG deleted file mode 100644 index 7f66c547..00000000 Binary files a/_todo/image/svn9a.PNG and /dev/null differ diff --git a/_todo/image/svn9b.PNG b/_todo/image/svn9b.PNG deleted file mode 100644 index f4968a6d..00000000 Binary files a/_todo/image/svn9b.PNG and /dev/null differ diff --git a/_todo/image/text1.bmp b/_todo/image/text1.bmp deleted file mode 100644 index c0feef36..00000000 Binary files a/_todo/image/text1.bmp and /dev/null differ diff --git a/_todo/image/text1.png b/_todo/image/text1.png deleted file mode 100644 index b86810cb..00000000 Binary files a/_todo/image/text1.png and /dev/null differ diff --git a/_todo/image/threadim1.png b/_todo/image/threadim1.png deleted file mode 100644 index e98531c6..00000000 Binary files a/_todo/image/threadim1.png and /dev/null differ diff --git a/_todo/image/threadim2.png b/_todo/image/threadim2.png deleted file mode 100644 index 02a51d29..00000000 Binary files a/_todo/image/threadim2.png and /dev/null differ diff --git a/_todo/image/tixfile.png b/_todo/image/tixfile.png deleted file mode 100644 index 13901b36..00000000 Binary files a/_todo/image/tixfile.png and /dev/null differ diff --git a/_todo/image/view.bmp b/_todo/image/view.bmp deleted file mode 100644 index 6df6a235..00000000 Binary files a/_todo/image/view.bmp and /dev/null differ diff --git a/_todo/image/view.png b/_todo/image/view.png deleted file mode 100644 index 6d368cda..00000000 Binary files a/_todo/image/view.png and /dev/null differ diff --git a/_todo/image/wiki1.PNG b/_todo/image/wiki1.PNG deleted file mode 100644 index d3bbc7d4..00000000 Binary files a/_todo/image/wiki1.PNG and /dev/null differ diff --git a/_todo/image/wiki2.PNG b/_todo/image/wiki2.PNG deleted file mode 100644 index 8396e1af..00000000 Binary files a/_todo/image/wiki2.PNG and /dev/null differ diff --git a/_todo/image/wiki3.PNG b/_todo/image/wiki3.PNG deleted file mode 100644 index 8ad5107e..00000000 Binary files a/_todo/image/wiki3.PNG and /dev/null differ diff --git a/_todo/image/wiki4.PNG b/_todo/image/wiki4.PNG deleted file mode 100644 index 076f3226..00000000 Binary files a/_todo/image/wiki4.PNG and /dev/null differ diff --git a/_todo/image/wiki5.PNG b/_todo/image/wiki5.PNG deleted file mode 100644 index 3629c48c..00000000 Binary files a/_todo/image/wiki5.PNG and /dev/null differ diff --git a/_todo/image/wiki6.PNG b/_todo/image/wiki6.PNG deleted file mode 100644 index c1bb80ca..00000000 Binary files a/_todo/image/wiki6.PNG and /dev/null differ diff --git a/_todo/image/window1.bmp b/_todo/image/window1.bmp deleted file mode 100644 index 35873b4f..00000000 Binary files a/_todo/image/window1.bmp and /dev/null differ diff --git a/_todo/image/window1.png b/_todo/image/window1.png deleted file mode 100644 index 6946dfc6..00000000 Binary files a/_todo/image/window1.png and /dev/null differ diff --git a/_todo/license.tex b/_todo/license.tex deleted file mode 100644 index 4be767e2..00000000 --- a/_todo/license.tex +++ /dev/null @@ -1,215 +0,0 @@ -\section{HISTORY OF THE SOFTWARE} - -Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. - -In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see http://www.zope.com). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a -non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. - -All Python releases are Open Source (see http://www.opensource.org for the Open Source Definition). - - - -\section{TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON} -\label{python_license} - -\subsection{PSF LICENSE AGREEMENT FOR PYTHON 2.3} - -\begin{enumerate} -\item This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python 2.3 software in source or binary form and its -associated documentation. - -\item Subject to the terms and conditions of this License Agreement, PSF -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 2.3 -alone or in any derivative version, provided, however, that PSF's -License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -2001, 2002, 2003 Python Software Foundation; All Rights Reserved" are -retained in Python 2.3 alone or in any derivative version prepared by -Licensee. - -\item In the event Licensee prepares a derivative work that is based on -or incorporates Python 2.3 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 2.3. - -\item PSF is making Python 2.3 available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -\item PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -\item This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -\item Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -\item By copying, installing or otherwise using Python 2.3, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. -\end{enumerate} - - -\subsection{BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0} - -\textbf{BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1} - -\begin{enumerate} -\item This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -\item Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -\item BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -\item BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -\item This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -\item This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -\item By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. -\end{enumerate} - - -\subsection{CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1} - -\begin{enumerate} -\item This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -\item Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the Internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the Internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -\item In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -\item CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -\item CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -\item This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -\item This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -\item By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - -\end{enumerate} - - - -\subsection{CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2} - - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - - diff --git a/_todo/programme/PythonSample.py b/_todo/programme/PythonSample.py deleted file mode 100644 index 9388a38f..00000000 --- a/_todo/programme/PythonSample.py +++ /dev/null @@ -1,4 +0,0 @@ -import sys -if "PythonSample" not in sys.modules : - PythonSample = imp.load_dynamic ('PythonSample', PythonSample.dll) - sys.modules ["PythonSample"] = PythonSample \ No newline at end of file diff --git a/_todo/programme/__init__.py b/_todo/programme/__init__.py deleted file mode 100644 index 155efa1d..00000000 --- a/_todo/programme/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -__rev_id__ = """__init__.py, version 1.0, 30/07/2007""" - -import sys -if sys.version_info[:2] != (2, 5): - print >> sys.stderr, "Sorry, PythonSample requires Python 2.5" - sys.exit (1) - -from PythonSample import * \ No newline at end of file diff --git a/_todo/programme/after.py b/_todo/programme/after.py deleted file mode 100644 index f56329b6..00000000 --- a/_todo/programme/after.py +++ /dev/null @@ -1,18 +0,0 @@ -import tkinter -root = tkinter.Tk () -l = tkinter.Label (text = "0 secondes") -l.pack () -sec = 0 -id = None - -def change_legende() : - global l - global sec - global id - sec += 1 - l.config (text = "%d secondes" % sec) - id = l.after (1000, change_legende) - -l.after (1000, change_legende) - -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/alltest.py b/_todo/programme/alltest.py deleted file mode 100644 index 959d7fdf..00000000 --- a/_todo/programme/alltest.py +++ /dev/null @@ -1,46 +0,0 @@ -# coding: latin-1 -import unittest -import os - -def get_test_file () : - """retourne la liste de tous les fichiers *.py commenant par test_""" - li = os.listdir (".") - li = [ l for l in li if "test_" in l and ".py" in l and \ - ".pyc" not in l and ".pyd" not in l] - return li - -def import_files (li) : - """pour un fichier test_*.py, cherche les classes Test... - et cre une suite de test pour ses mthodes commenant - par test..., retourne la suite de test""" - allsuite = [] - for l in li : - fi = l.replace (".py", "") - mo = __import__ (fi) - cl = dir (mo) - for c in cl : - if len (c) < 5 or c [:4] != "Test" : continue - # classe de test c - testsuite = unittest.TestSuite () - exec compile ("di = dir (mo." + c + ")", "", "exec") - for d in di : - if len (d) < 5 or d [:4] != "test" : continue - # method d.c - exec compile ("t = mo." + c + "(\"" + d + "\")", "", "exec") - testsuite.addTest (t) - allsuite.append ((testsuite, l)) - - return allsuite - -def main () : - """cre puis lance les suites de textes dfinis dans - des programmes test_*.py""" - li = get_test_file () - suite = import_files (li) - runner = unittest.TextTestRunner() - for s in suite : - print "running test for ", s [1] - runner.run (s [0]) - -if __name__ == "__main__" : - main () \ No newline at end of file diff --git a/_todo/programme/arbo.png b/_todo/programme/arbo.png deleted file mode 100644 index 088e387b..00000000 Binary files a/_todo/programme/arbo.png and /dev/null differ diff --git a/_todo/programme/bette_davis.GIF b/_todo/programme/bette_davis.GIF deleted file mode 100644 index ca19d0a9..00000000 Binary files a/_todo/programme/bette_davis.GIF and /dev/null differ diff --git a/_todo/programme/binary_file.py b/_todo/programme/binary_file.py deleted file mode 100644 index 6742e06a..00000000 --- a/_todo/programme/binary_file.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: latin-1 -import struct -# on enregistre un entier, un rel et 4 caractres -i = 10 -x = 3.1415692 -s = "ABCD" - -# criture -with open ("info.bin", "wb") as fb: - fb.write ( struct.pack ("i" , i) ) - fb.write ( struct.pack ("d" , x) ) - octets = s.encode("ascii") - fb.write ( struct.pack ("4s" , octets) ) - -# lecture -with open ("info.bin", "rb") as fb: - i = struct.unpack ("i", fb.read (4)) - x = struct.unpack ("d", fb.read (8)) - s = struct.unpack ("4s", fb.read (4)) - -# affichage pour vrifier que les donnes ont t bien lues -print(i) # affiche (10,) -print(x) # affiche (3.1415692000000002,) -print(s) # affiche (b'ABCD',) \ No newline at end of file diff --git a/_todo/programme/binary_file2.py b/_todo/programme/binary_file2.py deleted file mode 100644 index 2d04861e..00000000 --- a/_todo/programme/binary_file2.py +++ /dev/null @@ -1,32 +0,0 @@ -# coding: latin-1 -import struct -# on enregistre un entier, un rel et n caractres -i = 10 -x = 3.1415692 -s = "ABCDEDF" - -# criture -with open ("info.bin", "wb") as fb: - fb.write ( struct.pack ("i" , i) ) - fb.write ( struct.pack ("d" , x) ) - r = s.encode("utf-8") - fb.write ( struct.pack ("i" , len(r)) ) # on sauve la dimension de r - fb.write ( struct.pack ("{0}s".format(len(r)), r) ) - -# lecture -with open ("info.bin", "rb") as fb: - i = struct.unpack ("i", fb.read (4)) - x = struct.unpack ("d", fb.read (8)) - size = struct.unpack ("i", fb.read (4)) # on rcupre la dimension de s - size = size [0] # l est un tuple, on s'intresse son unique lment - s = struct.unpack ("{0}s".format(size), fb.read (size)) - -# affichage pour contrler -print(i) -print(x) -print(s) - -from struct import pack -print(len(pack('i', 0))) -print(len(pack('d', 0))) -print(len(pack('s', b'0'))) diff --git a/_todo/programme/chal_mono.gif b/_todo/programme/chal_mono.gif deleted file mode 100644 index 4ef603cb..00000000 Binary files a/_todo/programme/chal_mono.gif and /dev/null differ diff --git a/_todo/programme/classe_exemple.py b/_todo/programme/classe_exemple.py deleted file mode 100644 index fcbe1d22..00000000 --- a/_todo/programme/classe_exemple.py +++ /dev/null @@ -1,68 +0,0 @@ -# coding: latin-1 -# la premire ligne autorise les accents -class fromage : - - def __init__ (self, p,c,o) : - self.poids = p - self.couleur = c - self.odeur = o - - def decouper (self,nb) : - l = [] - for i in range (0,nb) : - f = fromage (self.poids/nb, \ - self.couleur, self.odeur) - l.append (f) - return l - - def __str__ (self) : - s = "poids : " + str (self.poids) - s += " couleur : " + str (self.couleur) - s += " odeur : " + str (self.odeur) - return s - - def __add__ (self,f) : - print("ajout fromage") - poids = self.poids + f.poids - couleur = [0,0,0] - for i in range (0,3) : - couleur [i] = (self.couleur [i] * self.poids \ - + f.couleur [i] * f.poids) / poids - odeur = (self.odeur * self.poids + \ - f.odeur * f.poids) / poids - couleur = ( couleur [0], couleur [1], couleur [2]) - return fromage (poids, couleur, odeur) - -class gruyere (fromage) : - def __init__ (self,p) : - fromage.__init__ (self, p, c = (150,150,0), o = 0.1) - - def __str__ (self) : - s = fromage.__str__(self) - s = "gruyre, " + s - return s - - def __add__ (self,f) : - print("ajout gruyre") - if not isinstance (f, gruyere) : - return fromage.__add__ (self, f) - else : - r = gruyere (self.poids + f.poids) - return r - -#-------------------------------------------- -fr = fromage (5.0, (255,0,0), 0.5) -fr2 = fromage (10.0, (0,255,0), 1) -fr3 = fr + fr2 -print(fr) -print(fr2) -print(fr3) -print("----------------------") -g = gruyere (3.0) -g2 = gruyere (7.0) -g3 = g + g2 -print(g) -print(g2) -print(g3) -print("----------------------") -print(fr2 + g) diff --git a/_todo/programme/classique.py b/_todo/programme/classique.py deleted file mode 100644 index ba56ac03..00000000 --- a/_todo/programme/classique.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter - -class MaFenetre : - def __init__(self, win) : - self.win = win - self.creation() - - def creation(self) : - b1 = tkinter.Button(self.win, text="bouton 1", command=self.commande_bouton1) - b2 = tkinter.Button(self.win, text="bouton 2", command=self.commande_bouton2) - b3 = tkinter.Button(self.win, text="disparition", command=self.disparition) - b1.grid(row=0, column=0) - b2.grid(row=0, column=1) - b3.grid(row=0, column=2) - self.lab = tkinter.Label(self.win, text = "-") - - def commande_bouton1(self) : - # on déplace l'objet lab de type Label - self.lab.configure(text = "bouton 1 appuyé") - self.lab.grid(row = 1, column = 0) - - def commande_bouton2(self) : - # on déplace l'objet lab de type Label - self.lab.configure(text = "bouton 2 appuyé") - self.lab.grid(row = 1, column = 1) - - def disparition(self) : - # on fait disparaître l'objet lab de type Label - self.lab.grid_forget() - -if __name__ == "__main__" : - root = tkinter.Tk() - f = MaFenetre(root) - root.mainloop() diff --git a/_todo/programme/classique_seq.py b/_todo/programme/classique_seq.py deleted file mode 100644 index fd8b3a82..00000000 --- a/_todo/programme/classique_seq.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter - -class MaFenetreSeq: - def __init__(self, win): - self.win = win - self.creation() - self.sequence = [] - - def creation(self): - b1 = tkinter.Button(self.win, text="bouton 1", command=self.commande_bouton1) - b2 = tkinter.Button(self.win, text="bouton 2", command=self.commande_bouton2) - b3 = tkinter.Button(self.win, text="remise à zéro", command=self.zero) - b1.grid(row=0, column=0) - b2.grid(row=0, column=1) - b3.grid(row=0, column=2) - self.lab = tkinter.Label(self.win, text = "-") - - def commande_bouton1(self): - # ajoute 1 à la liste self.sequence - self.sequence.append(1) - self.controle() - - def commande_bouton2(self): - # ajoute 2 à la liste self.sequence - self.sequence.append(2) - self.controle() - - def zero(self): - # on vide la liste self.sequence - self.sequence = [] - self.lab.grid_forget() - - def controle(self): - # on compare la liste sequence entre [1,2,1] et [2,2,1,1] - # dans ce cas, on fait apparaître l'objet lab - l = len(self.sequence) - if l >= 3 and self.sequence [l-3:] == [1,2,1]: - self.lab.configure(text = "séquence 1 2 1") - self.lab.grid(row = 1, column = 0) - elif l >= 4 and self.sequence [l-4:] == [2,2,1,1]: - self.lab.configure(text = "séquence 2 2 1 1") - self.lab.grid(row = 1, column = 1) - -if __name__ == "__main__": - root = tkinter.Tk() - f = MaFenetreSeq(root) - root.mainloop() \ No newline at end of file diff --git a/_todo/programme/combobox.py b/_todo/programme/combobox.py deleted file mode 100644 index f9fb8a35..00000000 --- a/_todo/programme/combobox.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter -import tkinter.ttk as ttk - -root = tkinter.Tk() - -o = ttk.Combobox(root, values=["ligne 1", "ligne 2", "ligne 3", "ligne 4"]) -o.pack () - -def print_file () : # voir le chapitre sur les événements - print(o.get()) - -b = tkinter.Button (root, text="print") -b.config (command = print_file) # idem -b.pack () - -help(tkinter.Button.__init__) - -root.mainloop() # idem diff --git a/_todo/programme/command.py b/_todo/programme/command.py deleted file mode 100644 index d46a006a..00000000 --- a/_todo/programme/command.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- -# la première ligne autorise les accents -import tkinter -root = tkinter.Tk () -b = tkinter.Button (text = "fonction change_legende") -b.pack () - -def change_legende () : - global b - b.config (text = "nouvelle légende") - -b.config (command = change_legende) -root.mainloop () diff --git a/_todo/programme/conversion.py b/_todo/programme/conversion.py deleted file mode 100644 index 2a307ca8..00000000 --- a/_todo/programme/conversion.py +++ /dev/null @@ -1,51 +0,0 @@ -import py2html -import os -import os.path - -py_page = """ - - - - -%s - - - -

    Programme %s

    -
    -%s -
    -cr avec py2html version:%s -

    -

    -""" - -l = os.listdir ("") -for f in l: - racine,ext = os.path.splitext (f) - if ext == ".py": - print "conversion of ", f - appliedstyle = py2html.readStyleFile(None) - data = py2html.file2HTML(f,"0",appliedstyle,False,"1") - block = py2html.makeBlock (data) - html = py_page % (f,f,block,py2html.__version__) - outfile = racine + ".html" - file = open(outfile,"w") - file.write(html) - file.close() -print "end" \ No newline at end of file diff --git a/_todo/programme/cube_class.py b/_todo/programme/cube_class.py deleted file mode 100644 index 64135fdd..00000000 --- a/_todo/programme/cube_class.py +++ /dev/null @@ -1,22 +0,0 @@ -class Fonction : - def calcul(self, x): - pass - def calcul_n_valeur(self, l) : - res = [ self.calcul(i) for i in l ] - return res - -class Carre (Fonction) : - def calcul(self, x): - return x*x - -class Cube (Fonction) : - def calcul(self, x): - return x*x*x - -li = [0,1,2,3] -print(li) # affiche [0, 1, 2, 3] - -l1 = Carre().calcul_n_valeur(li) # l1 vaut [0, 1, 4, 9] -l2 = Cube().calcul_n_valeur(li) # l2 vaut [0, 1, 8, 27] -print(l1) -print(l2) diff --git a/_todo/programme/cube_class2.py b/_todo/programme/cube_class2.py deleted file mode 100644 index 074a63a2..00000000 --- a/_todo/programme/cube_class2.py +++ /dev/null @@ -1,19 +0,0 @@ -class Fonction: - def calcul(self, x): - pass -class Carre(Fonction): - def calcul(self, x): - return x*x -class Cube(Fonction): - def calcul(self, x): - return x*x*x - -def calcul_n_valeur (l,f): - res = [ f(i) for i in l ] - return res - -l = [0,1,2,3] -l1 = calcul_n_valeur(l, Carre().calcul) # l1 vaut [0, 1, 4, 9] -l2 = calcul_n_valeur(l, Cube().calcul) # l2 vaut [0, 1, 8, 27] -print(l1) -print(l2) diff --git a/_todo/programme/dicho.py b/_todo/programme/dicho.py deleted file mode 100644 index 8ccb44ce..00000000 --- a/_todo/programme/dicho.py +++ /dev/null @@ -1,12 +0,0 @@ -def recherche_dichotomique (li, c) : - a,b = 0, len (li)-1 - while a <= b : - m = (a+b)//2 - if c == li [m] : return m - elif c < li [m] : b = m-1 # partie suprieure limine - else : a = m+1 # partie infrieure limine - return -1 # lment non trouv - -li = range (0,100,2) -print (recherche_dichotomique (li, 48)) # affiche 24 -print (recherche_dichotomique (li, 49)) # affiche -1 \ No newline at end of file diff --git a/_todo/programme/essai.txt b/_todo/programme/essai.txt deleted file mode 100644 index 10f095e4..00000000 --- a/_todo/programme/essai.txt +++ /dev/null @@ -1,57 +0,0 @@ --1/0= 0/1= 0.0 -1/2= 0.5 -2/3= 0.6666666666666666 -3/0= 4/1= 4.0 -5/2= 2.5 -6/3= 2.0 -7/0= 8/1= 8.0 -9/2= 4.5 -10/3= 3.3333333333333335 -11/0= 12/1= 12.0 -13/2= 6.5 -14/3= 4.666666666666667 -15/0= 16/1= 16.0 -17/2= 8.5 -18/3= 6.0 --1/0= 0/1= 0.0 -1/2= 0.5 -2/3= 0.6666666666666666 -3/0= 4/1= 4.0 -5/2= 2.5 -6/3= 2.0 -7/0= 8/1= 8.0 -9/2= 4.5 -10/3= 3.3333333333333335 -11/0= 12/1= 12.0 -13/2= 6.5 -14/3= 4.666666666666667 -15/0= 16/1= 16.0 -17/2= 8.5 -18/3= 6.0 --1/0= 0/1= 0.0 -1/2= 0.5 -2/3= 0.6666666666666666 -3/0= 4/1= 4.0 -5/2= 2.5 -6/3= 2.0 -7/0= 8/1= 8.0 -9/2= 4.5 -10/3= 3.3333333333333335 -11/0= 12/1= 12.0 -13/2= 6.5 -14/3= 4.666666666666667 -15/0= 16/1= 16.0 -17/2= 8.5 -18/3= 6.0 --1/-2=0.5 -0/-1=-0.0 -1/0=2/1=2.0 -3/2=1.5 --1/-2=0.5 -0/-1=-0.0 -1/0=2/1=2.0 -3/2=1.5 --1/-2=0.5 -0/-1=-0.0 -1/0=2/1=2.0 -3/2=1.5 diff --git a/_todo/programme/exemple.py b/_todo/programme/exemple.py deleted file mode 100644 index 9a056203..00000000 --- a/_todo/programme/exemple.py +++ /dev/null @@ -1,13 +0,0 @@ -import module_exemple - -c = module_exemple.exemple_classe () -print(c) -print(module_exemple.exemple_fonction()) -help (module_exemple) - - - - - - - diff --git a/_todo/programme/exemple2.py b/_todo/programme/exemple2.py deleted file mode 100644 index b2fd9d02..00000000 --- a/_todo/programme/exemple2.py +++ /dev/null @@ -1,6 +0,0 @@ -import module_exemple as alias - -c = alias.exemple_classe () -print c -print alias.exemple_fonction () -help (alias) \ No newline at end of file diff --git a/_todo/programme/exemple3.py b/_todo/programme/exemple3.py deleted file mode 100644 index 840981a2..00000000 --- a/_todo/programme/exemple3.py +++ /dev/null @@ -1,5 +0,0 @@ -from module_exemple import * - -c = exemple_classe () -print c -print exemple_fonction () \ No newline at end of file diff --git a/_todo/programme/exemple4.py b/_todo/programme/exemple4.py deleted file mode 100644 index 73529187..00000000 --- a/_todo/programme/exemple4.py +++ /dev/null @@ -1,6 +0,0 @@ -alias = __import__ ("module_exemple") - -c = alias.exemple_classe () -print c -print alias.exemple_fonction () -help (alias) \ No newline at end of file diff --git a/_todo/programme/exemple_bind.py b/_todo/programme/exemple_bind.py deleted file mode 100644 index 1459b088..00000000 --- a/_todo/programme/exemple_bind.py +++ /dev/null @@ -1,20 +0,0 @@ -import tkinter -root = tkinter.Tk() -b = tkinter.Button(text="appuyer sur une touche") -b.pack() - -def affiche_touche_pressee (evt) : - print("--------------------------- touche pressee") - print("evt.char = ", evt.char) - print("evt.keysym = ", evt.keysym) - print("evt.num = ", evt.num) - print("evt.x,evt.y = ", evt.x, ",", evt.y) - print("evt.x_root,evt.y_root = ", evt.x_root, ",", evt.y_root) - print("evt.widget = ", evt.widget) - -b.bind ("", affiche_touche_pressee) -b.bind ("", affiche_touche_pressee) -b.bind ("", affiche_touche_pressee) -b.focus_set () - -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/exemple_bind_my.py b/_todo/programme/exemple_bind_my.py deleted file mode 100644 index 9827bded..00000000 --- a/_todo/programme/exemple_bind_my.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter - -def affiche_touche_pressee(): - root.event_generate("<>", rooty=-5) - -def perso(evt): - print("perso", evt.y_root) - -root = tkinter.Tk() -b = tkinter.Button(text="clic", command=affiche_touche_pressee) -b.pack() -root.bind("<>", perso) # on intercepte un événement personnalisé -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/exemple_import.py b/_todo/programme/exemple_import.py deleted file mode 100644 index a1f867e8..00000000 --- a/_todo/programme/exemple_import.py +++ /dev/null @@ -1,20 +0,0 @@ -# coding: latin-1 -def import_fichier (module) : - import os.path - import sys - if os.path.exists (module) : # on teste l'existence du fichier - folder,name = os.path.split (module) # on obtient le rpertoire du module - if folder not in sys.path : - sys.path.append (folder) # on ajoute le rpertoire dans la liste - # des rpertoires autoriss - name = name.replace (".py", "") # on enlve l'extension - module = __import__ (name) # on importe le module - return module - else : - # si le fichier n'existe pas --> on lve une exception - raise ImportError ("impossible d'importer le module " + module) - -# on importe un module -mod = import_fichier ("module_exemple.py") -# on affiche l'aide associe -help (mod) \ No newline at end of file diff --git a/_todo/programme/exemple_menu.py b/_todo/programme/exemple_menu.py deleted file mode 100644 index 775b3d15..00000000 --- a/_todo/programme/exemple_menu.py +++ /dev/null @@ -1,40 +0,0 @@ -import tkinter -import tkinter.ttk -import tkinter.tix -root = tkinter.Tk () - -help(tkinter.tix) - -e = tkinter.Text (width = 50, height = 10) -e.pack () - -m = tkinter.Menu (root) - -sm1 = tkinter.Menu (root) -sm2 = tkinter.Menu (root) - -m.add_cascade (label = "sous-menu 1", menu = sm1) -m.add_cascade (label = "sous-menu 2", menu = sm2) - -nb = 0 - -def affiche(): - print ("fonction affiche") - -def calcul(): - print ("fonction calcul ", 3 * 4) - -def ajoute_bouton () : - global nb - nb += 1 - b = tkinter.Button (text = "bouton " + str (nb)) - b.pack () - -sm1.add_command (label = "affiche", command = affiche) -sm1.add_command (label = "calcul", command = calcul) -sm2.add_command (label = "ajoute_bouton", command = ajoute_bouton) -sm2.add_command (label = "fin", command = root.destroy) - -root.config (menu = m, width = 200) -root.title ("essai de menu") -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/exemple_pydoc.py b/_todo/programme/exemple_pydoc.py deleted file mode 100644 index dafbbf23..00000000 --- a/_todo/programme/exemple_pydoc.py +++ /dev/null @@ -1,32 +0,0 @@ -# coding: latin-1 -"""aide associe ce module, exemple d'utiliation de pydoc""" -import os.path -import os - -def pydoc_present () : - """teste la prsence du fichier pydoc.py""" - p = "c:\\python26\\lib\\pydoc.py""" - return os.path.exists (p) - -def pydoc_generation (file) : - """gnre la documentation associe au fichier file""" - if not pydoc_present () : - raise Exception ("pydoc n'est pas install") - os.system ("c:\\python26\\python c:\\python26\\lib\\pydoc.py -w " + file) - -class ExempleClass (object) : - """exemple de classe avec de la documentation - la classe contient comme attribut : - - li : liste quelconque - """ - def __init__ (self) : - object.__init__ (self) - self.li = ["un", "deux"] - def __str__ (self) : - """permet d'afficher la classe sous forme de chanes de caractres""" - return "li = " + str (self.li) - -if __name__ == "__main__" : - e = ExempleClass () - print e # affiche li = ['un', 'deux'] - pydoc_generation ("exemple_pydoc") \ No newline at end of file diff --git a/_todo/programme/extrpdf.py b/_todo/programme/extrpdf.py deleted file mode 100644 index a1b3044d..00000000 --- a/_todo/programme/extrpdf.py +++ /dev/null @@ -1,26 +0,0 @@ -from pdftools.pdffile import PDFDocument -from pdftools.pdftext import Text - -def contents_to_text (contents): - for item in contents: - if isinstance (item, type ([])): - for i in contents_to_text (item): - yield i - elif isinstance (item, Text): - yield item.text - -doc = PDFDocument ("declaration.pdf") -n_pages = doc.count_pages () -text = [] - -for n_page in range (1, (n_pages+1)): - print "Page", n_page - page = doc.read_page (n_page) - contents = page.read_contents ().contents - text.extend (contents_to_text (contents)) - -print "".join (text) - -f = open ("ok.txt", "w") -f.write ("".join (text)) -f.close () diff --git a/_todo/programme/fileex.py b/_todo/programme/fileex.py deleted file mode 100644 index fd098bf1..00000000 --- a/_todo/programme/fileex.py +++ /dev/null @@ -1,10 +0,0 @@ - -for i in range(0, 5): - try : - x, y = i-1, i-2 - print(f"{x}/{y}") - with open("essai.txt", "a") as f: - f.write(f"{x}/{y}=") - f.write(str((float (x)/y)) + "\n" ) # exception si y == 0 - except Exception as e: - print("erreur avec i = ", i, ",", e, f.closed) \ No newline at end of file diff --git a/_todo/programme/filelist.py b/_todo/programme/filelist.py deleted file mode 100644 index bb26dd75..00000000 --- a/_todo/programme/filelist.py +++ /dev/null @@ -1,42 +0,0 @@ -# coding: latin-1 -import glob -import os.path - -def liste_fichier_repertoire (folder, filter) : - # rsultats - file,fold = [], [] - - # recherche des fichiers obissant au filtre - res = glob.glob (folder + "\\" + filter) - - # on inclut les sous-rpertoires qui n'auraient pas t - # slectionns par le filtre - rep = glob.glob (folder + "\\*") - for r in rep : - if r not in res and os.path.isdir (r) : - res.append (r) - - # on ajoute fichiers et rpertoires aux rsultats - for r in res : - path = r - if os.path.isfile (path) : - # un fichier, rien faire part l'ajouter - file.append (path) - else : - # sous-rpertoire : on appelle nouveau la fonction - # pour retourner la liste des fichiers inclus - fold.append (path) - fi,fo = liste_fichier_repertoire (path, filter) - file.extend (fi) # on tend la liste des fichiers - fold.extend (fo) # on tend la liste des rpertoires - # fin - return file,fold - -folder = r"." -filter = "*.rst" -file,fold = liste_fichier_repertoire (folder, filter) - -for f in file : - print("fichier ", f) -for f in fold : - print("rpertoire ", f) \ No newline at end of file diff --git a/_todo/programme/filelist2.py b/_todo/programme/filelist2.py deleted file mode 100644 index cdb33463..00000000 --- a/_todo/programme/filelist2.py +++ /dev/null @@ -1,17 +0,0 @@ -# coding: latin-1 -import os - -def liste_fichier_repertoire (folder) : - file, rep = [], [] - for r, d, f in os.walk (folder) : - for a in d : rep.append (r + "/" + a) - for a in f : file.append (r + "/" + a) - return file, rep - -folder = r"." -file,fold = liste_fichier_repertoire (folder) - -for f in file : - print ("fichier ", f) -for f in fold : - print ("rpertoire ", f) \ No newline at end of file diff --git a/_todo/programme/filelist3.py b/_todo/programme/filelist3.py deleted file mode 100644 index 929fea7e..00000000 --- a/_todo/programme/filelist3.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: latin-1 -import os -import re - -s = r"D:\Dupre\_data\informatique\support\vba\image/vbatd1_4.png" -print re.compile ("[\\\\/]image[\\\\/].*[.]png").search(s) -print re.compile ("[\\\\/]image[\\\\/].*[.]png").match(s) - - -def liste_fichier_repertoire (folder) : - file, rep = [], [] - for r, d, f in os.walk (folder) : - #for a in d : rep.append (r + "/" + a) - for a in f : - e = r + "/" + a - if re.compile ("[\\\\/]image[\\\\/].*[.]png$").search(e) : - file.append (r + "/" + a) - return file, rep - -folder = r"D:\Dupre\_data\informatique" -file,fold = liste_fichier_repertoire (folder) - -for f in file : print "fichier ", f -for f in fold : print "rpertoire ", f \ No newline at end of file diff --git a/_todo/programme/filemp3.py b/_todo/programme/filemp3.py deleted file mode 100644 index f5e41416..00000000 --- a/_todo/programme/filemp3.py +++ /dev/null @@ -1,68 +0,0 @@ -# coding: latin-1 -import os -import re -import mutagen.mp3 -import mutagen.easyid3 - - -def infoMP3 (file, tags) : - """retourne des informations sur un fichier MP3 sous forme de - dictionnaire (dure, titre, artiste, ...)""" - a = mutagen.mp3.MP3(file) - b = mutagen.easyid3.EasyID3(file) - info = { "minutes":a.info.length/60, "nom":file } - for k in tags : - try: - info[k] = str(b[k][0]) - except ValueError: - continue - return info - -def all_files (repertoire, tags, ext = re.compile (".mp3$")) : - """retourne les informations pour chaque fichier d'un rpertoire""" - all = [] - for r, d, f in os.walk (repertoire) : - for a in f : - if not ext.search (a): - continue - t = infoMP3(r + "/" + a, tags) - if len(t) > 0: - all.append(t) - return all - -def heart_notitle_mots (all, avoid,sep,heart) : - """retourne trois rsultats - - les chansons dont le titre valide l'expression rgulire heart - - les chansons dont le titre valide l'expression rgulire avoid - - le nombre moyen de mots dans le titre d'une chanson""" - liheart, notitle = [], [] - nbmot, nbsong = 0,0 - for a in all : - if "title" not in a : - notitle.append (a) - continue - ti = a ["title"].lower () - if avoid.match (ti) : - notitle.append (a) - continue - if heart.search(ti): - liheart.append (a) - nbsong += 1 - nbmot += len ([ m for m in sep.split (ti) if len (m) > 0 ]) - nbsong = max(nbsong, 1) - return liheart, notitle, float (nbmot)/nbsong - -tags = "title album artist genre tracknumber".split () -all = all_files (r"D:\musique", tags) - -avoid = re.compile("^(((audio)?track( )?( - )?[0-9]{1,2})|(piste [0-9]{1,2}))$") -sep = re.compile("[- ,;!'.?&:]") -heart = re.compile("((heart)(?!((ache)|(land))))") -liheart, notitle, moymot = heart_notitle_mots (all, avoid, sep, heart) - -print("nombre de mots moyen par titre ", moymot) -print("somme des dure contenant heart ", sum([s ["minutes"] for s in liheart])) -print("chanson sans titre ", len (notitle)) -print("liste des titres ") -for s in liheart: - print(" ", s["title"]) \ No newline at end of file diff --git a/_todo/programme/filesel.py b/_todo/programme/filesel.py deleted file mode 100644 index b383a5bb..00000000 --- a/_todo/programme/filesel.py +++ /dev/null @@ -1,11 +0,0 @@ -import Tix as Tk -root = Tk.Tk () - -def command_print () : print box.cget("value") - -box = Tk.FileSelectBox (root) -box.config (directory="c:\\") -box.pack () -Tk.Button (root, text = "print", command = command_print).pack () - -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/fonction.py b/_todo/programme/fonction.py deleted file mode 100644 index c9c5161a..00000000 --- a/_todo/programme/fonction.py +++ /dev/null @@ -1,71 +0,0 @@ -# coding: latin-1 -"""ce programme dtermine toutes les fonctions dfinies dans -un programme et jamais appeles""" -import glob -import os -import re - - -def trouve_toute_fonction (s, exp, gr, expm = "^$") : - """ partir d'une chane de caractres correspondant - un programme Python, cette fonction retourne - une liste de 3-uples, chacun contient : - - le nom de la fonction - - (debut,fin) de l'expression dans la chane - - la ligne o elle a t trouve - - Paramtres: - - s : chane de caractres - - exp : chane de caractres correspond l'expression - - gr : numro de groupe correspondant au nom de la fonction - - expm : expression ngative - """ - exp = re.compile (exp) - res = [] - pos = 0 - r = exp.search (s, pos) # premire recherche - while r is not None : - temp = (r.groups()[gr], r.span(gr), r.group(gr)) - x = re.compile(expm.replace ("function", temp [0]) ) - if not x.match(temp[2]) : - # l'expression ngative n'est pas trouv, on peut ajouter ce rsultat - res.append(temp) - r = exp.search(s, r.end(gr)) # recherche suivante - return res - -def get_function_list_definition (s) : - """trouve toutes les dfinitions de fonctions""" - return trouve_toute_fonction (s, \ - "\ndef[ ]+([a-zA-Z_][a-zA-Z_0-9]*)[ ]*[(].*[)][ ]*[:]", 0) - -def get_function_list_call (s) : - """trouve tous les appels de fonctions""" - return trouve_toute_fonction (s, \ - "\n.*[=(,[{ .]([a-zA-Z_][a-zA-Z_0-9]*)(?![ ]?:)[ ]*[(].*[)]?", 0, \ - "^\\n[ ]*(class|def)[ ]+function.*$") - -def detection_fonction_pas_appelee (file) : - """retourne les couples de fonctions jamais appeles suivies - du numro de la ligne o elles sont dfinies""" - - f = open (file, "r") - li = f.readlines () - f.close () - sfile = "".join (li) - - funcdef = get_function_list_definition (sfile) - funccal = get_function_list_call (sfile) - f2 = [ p [0] for p in funccal ] - res = [] - for f in funcdef : - if f [0] not in f2 : - ligne = sfile [:f [1][0]].count ("\n") - res.append ( (f [0], ligne+2)) - return res - -def fonction_inutile () : # ligne 63 - pass - -file = __file__ -print(detection_fonction_pas_appelee(file)) - # affiche [('fonction_inutile', 63)] \ No newline at end of file diff --git a/_todo/programme/genchm.py b/_todo/programme/genchm.py deleted file mode 100644 index abd4dcdf..00000000 --- a/_todo/programme/genchm.py +++ /dev/null @@ -1,117 +0,0 @@ -# coding: latin-1 -"""genchm.py : gnration automatique du fichier d'aide chm""" -import genhelp -import os -htmlworkshop_path = "\"c:\\Program Files\\HTML Help Workshop\\hhc.exe\"" - -def g (s) : - """ajoute des guillements autour d'une chane de caractres""" - return "\"" + s + "\"" - -def genhhp (files, premierepage, titre, \ - hhp = "help.hhp", hhc = "help.hhc", hhk = "help.hhk") : - """gnre le fichier hpp dfinissant le fichier d'aide chm, - files est la liste des fichiers HTML - premierepage est la page afficher en premier - titre est le titre de l'aide""" - proj = """[OPTIONS] -Compatibility=1.1 -Full-text search=Yes -Contents file=""" + hhc + """ -Default Window=main -Default topic=""" + premierepage + """ -Index file=""" + hhk + """ -Language=0x40C French -Binary TOC=YES -Create CHI file=No -Title=""" + g (titre) + """ - -[WINDOWS] -main=""" + g (titre) + """, """ + g (hhc) + """, """ + g (hhk) + """ , """ + \ - g (premierepage) + """, """ + g (premierepage) + """,,,,,0x23520,,0x387e,,,,,,,,0 - -[FILES] -""" - for f in files : - proj += f + "\n" - - f = open (hhp, "w") - f.write (proj) - f.close () - -def gen_premierepage (files, titre, res = "index.html") : - """gnre la premire page de l'aide au format HTML""" - s = """""" + titre + """\n""" - s += "

    " + titre + "

    \n" - for f in files : - s += "" + f.replace (".html", "") + "
    \n" - s += "\n" - - f = open (res, "w") - f.write (s) - f.close () - -def genhh_input (entree, page, link = True) : - """retourne la chane de caractres associe une entre de la table des matires""" - res = """
  • """ - if link : res += """""" - res += """\n""" - return res - -def genhhc (files, premierepage, titre, hhc = "help.hhc") : - """gnre le fichier hhc, mme paramtre que pour hhp""" - res =""" - - - -
      """ - res += genhh_input (titre, premierepage, False) - res += "
        \n" - res += genhh_input ("modules", premierepage, False) - res += "
          \n" - for f in files : - res += genhh_input (f.replace (".html", ""), f) - res += "
        \n" - res += "
      \n" - res += "
    \n" - res += "\n" - - f = open (hhc, "w") - f.write (res) - f.close () - -def genhhk (files, premierepage, titre, hhk = "help.hhk") : - """gnre le fichier hhk, mme paramtre que pour hhp""" - res =""" - - - -
      """ - res += genhh_input (titre, premierepage) - res += "
        \n" - for f in files : - res += genhh_input (f.replace (".html", ""), f) - res += "
      \n" - res += "
    \n" - res += "\n" - - f = open (hhk, "w") - f.write (res) - f.close () - -def genchm (files, titre, \ - hhp = "help.hhp", hhc = "help.hhc", hhk = "help.hhk") : - """gnre le fichier d'aide complet""" - premierepage = "index.html" # gnre la page de garde - gen_premierepage (files, titre, premierepage) - files.append (premierepage) - genhhp (files, premierepage, titre) # gnre le fichier hhp - genhhc (files, premierepage, titre) # gnre le fichier hhc - genhhk (files, premierepage, titre) # gnre le fichier hhk - os.system (htmlworkshop_path + " " + hhp) # appelle HTML WorkShop en ligne de commande - -if __name__ == "__main__" : - files = [".\\genchm.py", ".\\genhelp.py", "os", "sys"] - res = genhelp.genhelp (files) - print res # ['genchm.html', 'genhelp.html', 'os.html', 'sys.html'] - genchm (res, "GenHelp") \ No newline at end of file diff --git a/_todo/programme/genhelp.py b/_todo/programme/genhelp.py deleted file mode 100644 index b8af6609..00000000 --- a/_todo/programme/genhelp.py +++ /dev/null @@ -1,65 +0,0 @@ -# coding: latin-1 -"""genhelp.py : gnration automatique de l'aide dans le rpertoire d'excution""" -import os -import sys -python_path = r"c:\python25\python" # constante -pydoc_path = r"c:\python25\lib\pydoc.py" # constante - -class ClassExemple : - """classe vide, exemple d'aide""" - def __init__ (self) : - """constructeur""" - pass - def methode (self) : - """unique mthode""" - return 1 - -def generate_help_file (f, pyt = python_path, pyd = pydoc_path) : - """gnre l'aide associe un fichier ou un module - le nom de ce fichier peut apparatre sans son extension ou alors - prcd de .\\ ou avec son chemin complet - pyt est le rpertoire de python - pyd est l'emplacement de pydoc.py""" - s = "call " + pyt + " " + pyd + " -w " + f - os.system (s) - -def replace_firstpage (file, page) : - """la gnration de l'aide chm s'arrte avant la fin si le lien index - est laiss dans les pages gnres par pydoc, on le remplace par une page - comme index.html""" - f = open (file, "r") - li = f.readlines () - f.close () - f = open (file, "w") - for l in li : - f.write (l.replace ("""index""", page)) - f.close () - -def genhelp (files, pyt = python_path, pyd = pydoc_path, firstpage = "index.html") : - """gnre l'aide associe des fichiers ou des modules, - un fichier se distingue d'un module par son extension, - retourne la liste des fichiers gnrs, - pyt est le rpertoire de python - pyd est l'emplacement de pydoc.py - firstpage voir fonction replace_firstpage""" - res = [] - for f in files : - print "gnration de l'aide de ", f - if ".py" in f : # fichier - generate_help_file (f, pyt, pyd) - g = f.split ("\\") # ne garde que le nom de fichier et non son chemin - page = g [ len (g)-1].replace (".py", ".html") - else : # module - generate_help_file (f, pyt, pyd) - page = f + ".html" - res.append (page) - replace_firstpage (page, firstpage) - return res - -if __name__ == "__main__" : - import sys - import os - - files = [".\\genchm.py", ".\\genhelp.py", "os", "sys"] - res = genhelp (files) - print res # ['genchm.html', 'genhelp.html', 'os.html', 'sys.html'] \ No newline at end of file diff --git a/_todo/programme/graphplot.py b/_todo/programme/graphplot.py deleted file mode 100644 index f608923a..00000000 --- a/_todo/programme/graphplot.py +++ /dev/null @@ -1,86 +0,0 @@ -# coding: latin-1 - -import sys -import os - -default_path = r"C:\Program Files\gp423win32\gnuplot\bin\pgnuplot.exe" -default_temp_dir = "tempgnuplot" -imagenumber = 0 - -def execute_script_gnuplot (scr) : - global default_temp_dir - global imagenumber - global default_path - - if not os.path.exists (default_temp_dir) : os.mkdir (default_temp_dir) - - # avant - scr = "set term png\n" + scr - image = default_temp_dir + ("/image_%05d.png" % imagenumber) - imagenumber += 1 - scr = "set out \"" + image + "\"\n" + scr - - # aprs - scr += "show out\n" - scr += "exit\n" - - name = default_temp_dir + "/gnuscript.txt" - f = open (name, "w") - f.write (scr) - f.close () - - line = default_path + " " + name - os.system (line) - - return image - -def build_script_gnuplot (series, seriesname, title = None, \ - xlabel = None, ylabel = None, histo = False) : - global default_temp_dir - global default_path - - if not os.path.exists (default_temp_dir) : os.mkdir (default_temp_dir) - scr = "" - - if xlabel != None : scr += "set xlabel \"" + xlabel + "\"\n" - if ylabel != None : scr += "set ylabel \"" + ylabel + "\"\n" - if title != None : scr += "set title \"" + title + "\"\n" - - scr += "set grid\n" - if histo : scr += "set style data histograms\n" - else : scr += "set style data lines\n" - scr += "plot " - - id = 0 - for s,lab in zip (series, seriesname) : - name = default_temp_dir + "/series%d.txt" % (id) - id += 1 - f = open (name, "w") - for l in s : - if histo : f.write ("%f\n" % (l [1])) - else : f.write ("%f\t%f\n" % (l [0], l [1])) - f.close () - scr += "\"" + name + "\" title \"" + lab + "\", " - scr = scr [:len (scr)-2] - scr += "\n" - - return execute_script_gnuplot (scr) - - -if __name__ == "__main__" : - print "chemin pour gnuplot ", default_path - - series = [ [], [] ] - for i in range (0, 100) : - x = float (i) / 100 - y = x ** 0.5 - z = 1.0 - y - series [0].append ( (x,y) ) - series [1].append ( (x,z) ) - - image = build_script_gnuplot (series, ["serie 1", "serie 2"], \ - xlabel="abscisses", ylabel="ordonnes", histo = False) - print "image ", image - image = build_script_gnuplot (series, ["serie 1", "serie 2"], \ - xlabel="abscisses", ylabel="ordonnes", histo = True) - print "image ", image diff --git a/_todo/programme/hal_python.iss b/_todo/programme/hal_python.iss deleted file mode 100644 index 6cb880f2..00000000 --- a/_todo/programme/hal_python.iss +++ /dev/null @@ -1,100 +0,0 @@ -; section non commente -[Setup] -AppName=HalPython -AppVerName=HalPython 1.5.1162 -AppPublisher=Xavier Dupr -AppPublisherURL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -AppSupportURL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -AppUpdatesURL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -DefaultDirName={pf}/HalPython -DefaultGroupName=HalPython -OutputDir=D:\Dupre\_data\site\hal_python\executable -OutputBaseFilename=setup_HalPython_py25 -Compression=lzma -SolidCompression=yes -VersionInfoVersion=1.0.0 - -[Code] - -; cette fonction retourne le chemin d'installation de Python 2.5 -; le rsultat est vide si celui-ci n'a pas t install -; le chemin est celui stock dans la cl de registre -; HKLM\Software\Python\PythonCore\2.5\InstallPath -function GetPythonPath(Param: String): String; -begin - Result := ''; - Result := ExpandConstant('{reg:HKLM\Software\Python\PythonCore\2.5\InstallPath,|}'); - if Result <> '' then - Result := Result + '\pythonw.exe'; -end; - -; cette fonction retourne {win}\system32\msiexec.exe -; si Python 2.5 a t install, vide sinon -function GetPythonPathExec(Param: String): String; -begin - Result := GetPythonPath () ; - if Result <> '' then - Result := ExpandConstant('{win}\system32\msiexec.exe') ; -end; - -; cls de registre -; mmorise le rpertoire d'installation -; et le numro de version -[Registry] -Root: HKLM; Subkey: "SOFTWARE\HalPython\InstallPath"; ValueType: string; ValueName: ""; - ValueData: "{app}"; Flags: uninsdeletekey -Root: HKLM; Subkey: "SOFTWARE\HalPython\Version"; ValueType: string; ValueName: ""; - ValueData: "1.5.1162"; Flags: uninsdeletekey - -; icne sur le bureau -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; - Flags: checkedonce - -; fichiers -[Files] -; le module en question -Source: "..\hal_dll.dll"; DestDir: "{app}\hal_python"; -Source: "..\hal_dll_ext.dll"; DestDir: "{app}\hal_python"; -Source: "..\hal_dll_model.dll"; DestDir: "{app}\hal_python"; -Source: "..\hal_python.dll"; DestDir: "{app}\hal_python"; -Source: "..\wxwindows_old.dll"; DestDir: "{app}\hal_python"; -Source: "..\boost_python.dll"; DestDir: "{app}\hal_python"; -Source: "..\_graphviz_draw.exe"; DestDir: "{app}\hal_python"; -Source: "..\_hal_script.exe"; DestDir: "{app}\hal_python"; -Source: "..\hal_python.py"; DestDir: "{app}\hal_python"; -Source: "..\install\__init__.py"; DestDir: "{app}\hal_python"; -Source: "..\install\setup.py"; DestDir: "{app}"; -Source: "..\_test\temp\hal_python.chm"; DestDir: "{app}"; - -; les fichiers annexes -Source: "hal_python.url"; DestDir: "{app}"; URL de l'application -Source: "pyscripter.chm"; DestDir: "{app}"; aide de l'diteur PyScripter -Source: "PyScripter.exe"; DestDir: "{app}"; diteur PyScripter -Source: "python-2.5.2.msi"; DestDir: "{app}"; installateur Python 2.5 -Source: "sample.bat"; DestDir: "{app}"; fichier de commande -Source: "sample.py"; DestDir: "{app}"; exemple de programme - -; cration des icnes -[Icons] -Name: "{group}\PyScripter"; Filename: "{app}\PyScripter.exe"; WorkingDir: "{app}" -Name: "{group}\PyScripter Help"; Filename: "{app}\pyscripter.chm"; WorkingDir: "{app}" -Name: "{group}\Help"; Filename: "{app}\hal_python.chm"; WorkingDir: "{app}" -Name: "{group}\smallest sample with PyScripter"; Filename: "{app}\small_sample.bat"; WorkingDir: "{app}" -Name: "{group}\Website"; Filename: "{app}\hal_python.url" -Name: "{group}\uninstall"; Filename: "{uninstallexe}"; WorkingDir: "{app}" - -[Run] -; installe Python 2.5 si GetPythonPathExec retourne un rsultat non vide -; passe l'instruction suivante sinon -Filename: "{code:GetPythonPathExec}"; Parameters: "/i ""{app}\python-2.5.2.msi"" /qr ALLUSERS=1"; - StatusMsg: "Installing Python 2.5..."; Flags: skipifdoesntexist - -; installe le module si GetPythonPath retourne un rsultat non vide -; passe l'instruction suivante sinon -; excute en fait l'insttruction python setup.py install -Filename: "{code:GetPythonPath}"; Parameters:"setup.py install"; WorkingDir: "{app}"; - StatusMsg: "Installing HalPython for Python 2.5..." - -; supprime l'installation de Python 2.5 -Filename: "{cmd}"; Parameters: "/c del python-2.5.2.msi"; WorkingDir: "{app}"; diff --git a/_todo/programme/hal_python_update.iss b/_todo/programme/hal_python_update.iss deleted file mode 100644 index 5d5b9c10..00000000 --- a/_todo/programme/hal_python_update.iss +++ /dev/null @@ -1,86 +0,0 @@ -; section non commente -[Setup] -AppName=HalPython -AppVerName=HalPython 1.5.1162 -AppPublisher=Xavier Dupr -AppPublisherURL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -AppSupportURL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -AppUpdatesURL=http://www.xavierdupre.fr/hal_python/hal_python_help_html/index.html -DefaultDirName={pf}/HalPython -DefaultGroupName=HalPython -OutputDir=D:\Dupre\_data\site\hal_python\executable -OutputBaseFilename=setup_HalPython_update_py25 -Compression=lzma -SolidCompression=yes -VersionInfoVersion=1.0.0 - -[Code] -function GetPythonPath(Param: String): String; -begin - Result := ''; - Result := ExpandConstant('{reg:HKLM\Software\Python\PythonCore\2.5\InstallPath,|}'); - if Result <> '' then - Result := Result + '\pythonw.exe'; -end; - -function GetHalPythonPath(Param: String): String; -begin - Result := ''; - Result := ExpandConstant ('{reg:HKLM\Software\HalPython\InstallPath,|}') ; -end; - -function InitializeSetup(): Boolean; -begin - Result := True ; - MsgBox (GetPythonPath (''), mbConfirmation, MB_OK) ; - MsgBox (GetHalPythonPath (''), mbConfirmation, MB_OK) ; - if GetPythonPath ('') = '' then begin - MsgBox('Python 2.5 has not been installed. You should download - the complete Setup with Python 2.5 included instead of updating.', mbError, MB_OK) ; - Result := False ; - end else if GetHalPythonPath ('') = '' then begin - MsgBox('HalPython for Python 2.5 has not been installed. - You should download the complete Setup with Python 2.5 included instead of updating.', - mbError, MB_OK) ; - Result := False ; - end -end; - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; - Flags: checkedonce - -[Files] -Source: "..\hal_dll.dll"; DestDir: "{app}\hal_python"; -Source: "..\hal_dll_ext.dll"; DestDir: "{app}\hal_python"; -Source: "..\hal_dll_model.dll"; DestDir: "{app}\hal_python"; -Source: "..\hal_python.dll"; DestDir: "{app}\hal_python"; -Source: "..\wxwindows_old.dll"; DestDir: "{app}\hal_python"; -Source: "..\boost_python.dll"; DestDir: "{app}\hal_python"; -Source: "..\_graphviz_draw.exe"; DestDir: "{app}\hal_python"; -Source: "..\_hal_script.exe"; DestDir: "{app}\hal_python"; -Source: "..\hal_python.py"; DestDir: "{app}\hal_python"; -Source: "..\install\__init__.py"; DestDir: "{app}\hal_python"; -Source: "..\install\setup.py"; DestDir: "{app}"; -Source: "hal_python.url"; DestDir: "{app}"; -Source: "small_sample.bat"; DestDir: "{app}"; -Source: "sample.py"; DestDir: "{app}"; -Source: "..\_test\temp\hal_python.chm"; DestDir: "{app}"; - -[Registry] -Root: HKLM; Subkey: "SOFTWARE\HalPython\InstallPath"; ValueType: string; ValueName: ""; - ValueData: "{app}"; Flags: uninsdeletekey -Root: HKLM; Subkey: "SOFTWARE\HalPython\Version"; ValueType: string; ValueName: ""; - ValueData: "1.5.1162"; Flags: uninsdeletekey - -[Icons] -Name: "{group}\PyScripter"; Filename: "{app}\PyScripter.exe"; WorkingDir: "{app}" -Name: "{group}\PyScripter Help"; Filename: "{app}\pyscripter.chm"; WorkingDir: "{app}" -Name: "{group}\Help"; Filename: "{app}\hal_python.chm"; WorkingDir: "{app}" -Name: "{group}\smallest sample with PyScripter"; Filename: "{app}\small_sample.bat"; WorkingDir: "{app}" -Name: "{group}\Website"; Filename: "{app}\hal_python.url" -Name: "{group}\uninstall"; Filename: "{uninstallexe}"; WorkingDir: "{app}" - -[Run] -Filename: "{code:GetPythonPath}"; Parameters:"setup.py install"; WorkingDir: "{app}"; - StatusMsg: "Installing HalPython for Python 2.5..." diff --git a/_todo/programme/htmlnavi.py b/_todo/programme/htmlnavi.py deleted file mode 100644 index 13d6814b..00000000 --- a/_todo/programme/htmlnavi.py +++ /dev/null @@ -1,16 +0,0 @@ -mat = ["Victor Hugo 6".split (), "Marcel Proust 3".split () ] -f = open ("tableau.html", "w") -f.write ("\n") -f.write ("\n") -for m in mat : - f.write ("") - for c in m : - f.write ("") - f.write ("\n") -f.write ("
    " + c + "
    ") -f.close () - -import os -os.system ("\"C:\\Program Files\\Mozilla Firefox\\firefox.exe\" tableau.html") -os.system ("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\"" \ - " d:\\temp\\tableau.html") \ No newline at end of file diff --git a/_todo/programme/import_c_module.py b/_todo/programme/import_c_module.py deleted file mode 100644 index 6b28d1d2..00000000 --- a/_todo/programme/import_c_module.py +++ /dev/null @@ -1,155 +0,0 @@ -# coding: latin-1 -""" -import d'un module C (un fichier), inclut la recompilation -si le module a volu depuis sa dernire compilation -""" - -import os, sys, re - -def _find_compiled_file (path, name) : - """cherche un fichier compil""" - ver = sys.version_info - st = "%d.%d" % ver [:2] - name = os.path.splitext (name) [0] - exp = re.compile (name + "[.]o$") - file, rep = [], [] - for r, d, f in os.walk (path) : - if st not in r : continue - for a in f : - if exp.search (a) : - return r,a - return None,None - -def import_c_module (name, mingw = r"c:\MinGW\bin", cpp = True, remove = False, path = None) : - """ - @ingroup SQLAppModels - import d'un module C - @param name nom du module C (nom du fichier sans extension, sans chemin non plus) - @param mingw emplacement du compilateur mingw - @param cpp c++ file? - @param remove remove the file first before compiling - @param path if the file is not found, try to look into this folder - @return objet module - - @warning remove = True must be used when the module is compiled for the first time. - Otherwise, the module is already loaded and impossible to remove until Python is closed. - """ - if os.path.splitext (name) [1] == "" : - if cpp : - name += ".cpp" - ext = "cpp" - else : - name += ".c" - ext = "c" - else : - ext = os.path.splitext (name) [1] [1:] - - mfile = name - mod = os.path.splitext (mfile) [0] - if path != None : - mypath = os.path.normpath (os.path.realpath (path)) - allpath = [mypath, "."] - else : allpath = ["."] - - for p in sys.path : - if p not in allpath : allpath.append (p) - - for path in allpath : - whole = os.path.join (path, name) - if os.path.exists (whole) : - break - else : - path_tried = u"\n".join (allpath) - raise ImportError ("unable to find file %s in any import path:\n%s" \ - % (name, path_tried)) - - if sys.platform == "win32" : fsec = mod + ".pyd" - else : fsec = mod + ".so" - - if path not in sys.path : - sys.path.append (path) - - comp = os.path.join (path, fsec) - if not os.path.exists (comp) : - cond = True - resa = "not found" - else : - if remove : - os.remove (comp) - cond = True - resa = "remove" - else : - r,f = _find_compiled_file (path, mfile) - if f != None : - wholeo = os.path.join (r,f) - datec = os.path.getmtime (whole) - date = os.path.getmtime (wholeo) - cond = datec > date - resa = "date" - else : - cond = True - resa = "f == None" - - if cond : - mfile = mod - - file = (""" - # coding: latin-1 - from distutils.core import setup - from distutils.core import Extension - - setup(name = '%s', - version = '0.1', - ext_modules = [Extension('%s', ['%s.%s']), ], - url = '', - author = '', - author_email = '...', - ) - """ % (mfile,mfile,mfile,ext)).replace (" ", "") - wr = os.path.join (path, "setup.py") - f = open (wr, "w") - f.write (file) - f.close () - - env = os.getenv ("PATH") - if mingw not in env : - os.putenv ("PATH", env + ";" + mingw) - - cwd = os.getcwd () - os.chdir (path) - - py = sys.executable.replace ("pythonw.exe", "python.exe") - if sys.platform == "win32" : - cmd = "%s setup.py build_ext --inplace -c mingw32" % (py) - else : cmd = "%s setup.py build_ext --inplace" % (py) - child_stdin, stdout, child_stderr = os.popen3 (cmd) - res = stdout.read () - err = child_stderr.read () - stdout.close () - - os.chdir (cwd) - - if len (err) > 0 : - message = "\nOUTPUT:\n" + res + "\n\n" - message += "ERR:\n" + err - if "error" in err : - message += "unable to compile %s (resa %s)\n%s" % (name, resa, message) - print (message) - raise ImportError (message) - else : - print (message) - - mod = __import__ (mfile) - return mod - - else : - mfile = mod - mod = __import__ (mfile) - return mod - -if __name__ == "__main__" : - sample_module = import_c_module ("sample_module", cpp = True) - print sample_module - - print sample_module.exemple("e") - print sample_module.exemple2() \ No newline at end of file diff --git a/_todo/programme/integrale.py b/_todo/programme/integrale.py deleted file mode 100644 index 3f94aedd..00000000 --- a/_todo/programme/integrale.py +++ /dev/null @@ -1,14 +0,0 @@ -import random # import du module random : simulation du hasard -import math # import du module math : fonctions mathmatiques - -def integrale_monte_carlo (a,b,f,n) : - somme = 0.0 - for i in range (0,n) : - x = random.random () * (b-a) + a - y = f(x) - somme += f(x) - return somme / n - -def racine (x) : return math.sqrt (x) - -print integrale (0,1,racine,100000) \ No newline at end of file diff --git a/_todo/programme/interface_exemple.py b/_todo/programme/interface_exemple.py deleted file mode 100644 index 97463fe1..00000000 --- a/_todo/programme/interface_exemple.py +++ /dev/null @@ -1,49 +0,0 @@ -import Tkinter as T -root = T.Tk () - - -l = T.Label (text = "lkfjhsdfkds") -l.pack () - -b = T.Button () -b.pack () - -e = T.Entry () -e.pack () -e.insert (0, "texte") -print "e = ", e.get () - -t = T.Text () -t.pack () -t.config (width = 100, height = 10) - -i = T.IntVar () -c = T.Checkbutton (text = "coche", variable = i) -c.pack () -i.set (1) - -j = T.IntVar () -r1 = T.Radiobutton (text = "option1", variable = j, value = 1) -r2 = T.Radiobutton (text = "option2", variable = j, value = 2) -r3 = T.Radiobutton (text = "option3", variable = j, value = 2) -j.set (2) -r1.pack () -r2.pack () -r3.pack () - -l = T.Listbox () -l.pack (side = T.RIGHT) -l.insert (0, "ligne") -l.insert (1, "colonne") - -im = T.PhotoImage (file = "chal_mono.GIF") -b.config (image = im) - -def affiche () : - t.insert ("0.0", "bravo") - s = t.get ("0.0", "end") - print s - -b.config (command = affiche) - -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/listebar.py b/_todo/programme/listebar.py deleted file mode 100644 index 845aa40c..00000000 --- a/_todo/programme/listebar.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter -import tkinter.scrolledtext -root = tkinter.Tk () - -o = tkinter.scrolledtext.ScrolledText (root) -for k in range (0,100) : - o.insert (tkinter.END, "ligne " + str (k)) -o.pack () - -def print_file () : # voir chapitre sur les événements - print (o.selection_get ()) # idem - -b = tkinter.Button (root, text = "print") -b.config (command = print_file) # idem -b.pack () - -root.mainloop () # idem \ No newline at end of file diff --git a/_todo/programme/listst.py b/_todo/programme/listst.py deleted file mode 100644 index 0d20c881..00000000 --- a/_todo/programme/listst.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter - -class MaListbox(tkinter.Listbox): - def __init__(self, master = None, cnf=None, **kw): - if cnf is None: - cnf = {} - tkinter.Listbox.__init__(self, master, cnf, **kw) - self.bind("", self.mouvement) - self.pos = None # mémoire l'ancienne position du curseur - def mouvement(self, ev): - pos = self.nearest(ev.y) # nouvelle position du curseur - if pos < 0 or pos >= self.size(): return - if self.pos != pos: - if self.pos != None: self.itemconfig(self.pos, bg='') - self.itemconfigure(pos, bg='gray') - self.pos = pos - -root = tkinter.Tk() -b = MaListbox() -b.insert("end", "ligne 1") -b.insert("end", "ligne 2") -b.insert("end", "ligne 3") -b.pack() -b.focus_set() -root.mainloop() \ No newline at end of file diff --git a/_todo/programme/mail.py b/_todo/programme/mail.py deleted file mode 100644 index ddb823d9..00000000 --- a/_todo/programme/mail.py +++ /dev/null @@ -1,39 +0,0 @@ -import smtplib -from email.mime.multipart import MIMEMultipart -from email.mime.base import MIMEBase -from email.mime.text import MIMEText -from email.utils import formatdate -from email import encoders -import os - - -def envoyer_mail (aqui, sujet, contenu, files = []): - de = "email de l'auteur" - msg = MIMEMultipart() - msg['From'] = de - msg['To'] = aqui - msg['Date'] = formatdate (localtime = True) - msg['Subject'] = sujet - - msg.attach(MIMEText(contenu)) - for file in files: - part = MIMEBase('application', 'octet-stream') - with open(file,'rb') as f: - content = f.read() - part.set_payload(content) - encoders.encode_base64(part) - part.add_header('Content-Disposition', \ - f'attachment; filename="{os.path.basename(file)}"') - msg.attach(part) - - smtp = smtplib.SMTP("smtp.gmail.com", 587) - smtp.ehlo() - smtp.starttls() - smtp.ehlo() - smtp.login("login", "mot_de_passe") - - smtp.sendmail(de, aqui, msg.as_string()) - smtp.close() - - -envoyer_mail("destinataire", "sujet","contenu", ["mail.py"]) diff --git a/_todo/programme/matrice.py b/_todo/programme/matrice.py deleted file mode 100644 index 0982ff6f..00000000 --- a/_todo/programme/matrice.py +++ /dev/null @@ -1,58 +0,0 @@ -# coding: latin-1 -s = "case11;case12;case13|case21;case22;case23" -ligne = s.split ("|") -mat = [ l.split (";") for l in ligne ] -print mat -ligne = [ ";".join (l) for l in mat ] -s = "|".join (ligne) -print s - -def fonction (x) : return x*x - -li = [ 0, 434, 43, 6436, 5 ] -m = 0 -for i in range (0, len (li)) : - if li [m] < li [i] : m = i -print li [m] - - -k = [ (li [i],i) for i in range (0, len (li)) ] -print k -print max (k) - -def recherche (li, c) : - for i in range (0, len (li)) : - if li [i] == c : return i - return -1 -print recherche (li, 43) - -for i in range (0, len (li)) : - pos = i - for j in range (i+1, len (li)) : - if li [j] < li [pos] : pos = j - ech = li [pos] - li [pos] = li [i] - li [i] = ech -print li - -li = ["un", "deux", "un", "trois"] -d = { } -for l in li : - if l not in d : d [l] = 1 - else : d [l] += 1 -print d # affiche {'un': 2, 'trois': 1, 'deux': 1} - -mat = [ [1,1,1], [2,2,2], [1,1,1]] -d = { } -for l in mat : - k = str (l) - if k not in d : d [k] = 1 - else : d [k] += 1 -print d # affiche {'[1, 1, 1]': 2, '[2, 2, 2]': 1} - -li = ["un", "deux", "un", "trois"] -d = { } -for i in range (0, len (li)) : - if li [i] not in d : d [li [i]] = [ i ] - else : d [li [i]].append (i) -print d # affiche {'un': [0, 2], 'trois': [3], 'deux': [1]} diff --git a/_todo/programme/mesmodules/__init__.py b/_todo/programme/mesmodules/__init__.py deleted file mode 100644 index d6b8f750..00000000 --- a/_todo/programme/mesmodules/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -print "y" -import part1.niveaudeux \ No newline at end of file diff --git a/_todo/programme/mesmodules/extension.py b/_todo/programme/mesmodules/extension.py deleted file mode 100644 index dee9c5cd..00000000 --- a/_todo/programme/mesmodules/extension.py +++ /dev/null @@ -1 +0,0 @@ -"""mesmodules/extension.py""" \ No newline at end of file diff --git a/_todo/programme/mesmodules/part1/__init__.py b/_todo/programme/mesmodules/part1/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/_todo/programme/mesmodules/part1/niveaudeux.py b/_todo/programme/mesmodules/part1/niveaudeux.py deleted file mode 100644 index 44703e9d..00000000 --- a/_todo/programme/mesmodules/part1/niveaudeux.py +++ /dev/null @@ -1 +0,0 @@ -"""mesmodules/part1/niveaudeux.py""" \ No newline at end of file diff --git a/_todo/programme/mesmodules/part2/__init__.py b/_todo/programme/mesmodules/part2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/_todo/programme/mesmodules/part2/niveaudeuxbis.py b/_todo/programme/mesmodules/part2/niveaudeuxbis.py deleted file mode 100644 index cb34c775..00000000 --- a/_todo/programme/mesmodules/part2/niveaudeuxbis.py +++ /dev/null @@ -1 +0,0 @@ -"""mesmodules/part2/niveaudeuxbis.py""" \ No newline at end of file diff --git a/_todo/programme/modinit.py b/_todo/programme/modinit.py deleted file mode 100644 index 484464a4..00000000 --- a/_todo/programme/modinit.py +++ /dev/null @@ -1,6 +0,0 @@ -import mesmodules.extension -#import mesmodules.part1.niveaudeux -import mesmodules.part2.niveaudeuxbis - -help (mesmodules.part1.niveaudeux) - diff --git a/_todo/programme/module_exemple.py b/_todo/programme/module_exemple.py deleted file mode 100644 index be2a8b48..00000000 --- a/_todo/programme/module_exemple.py +++ /dev/null @@ -1,13 +0,0 @@ -# coding: latin-1 -"""exemple de module, aide associe""" - -exemple_variable = 3 - -def exemple_fonction () : - """exemple de fonction""" - return 0 - -class exemple_classe : - """exemple de classe""" - def __str__ (self) : - return "exemple_classe" \ No newline at end of file diff --git a/_todo/programme/new_delete.py b/_todo/programme/new_delete.py deleted file mode 100644 index 857f4737..00000000 --- a/_todo/programme/new_delete.py +++ /dev/null @@ -1,21 +0,0 @@ -class CreationDestruction (object) : - - def __init__ (self) : - print("constructeur") - - def __new__ (self) : - print("__new__") - return object.__new__ (self) - - def __del__ (self) : - print("__del__") - -print("a") -m = CreationDestruction () -print("b") -m2 = m -print("c") -del m -print("d") -del m2 -print("e") diff --git a/_todo/programme/odbc_1.py b/_todo/programme/odbc_1.py deleted file mode 100644 index ff4ab5b1..00000000 --- a/_todo/programme/odbc_1.py +++ /dev/null @@ -1,14 +0,0 @@ -import odbc -cx = odbc.odbc("mysqlperso") -cur = cx.cursor() - -cur.execute (""" -CREATE TABLE ELEVE ( - num integer primary key, - nom varchar (30), - prenom varchar (30), - date date, - adresse varchar (100), - codepays integer, - classe integer) -""") \ No newline at end of file diff --git a/_todo/programme/odbc_2.py b/_todo/programme/odbc_2.py deleted file mode 100644 index 6123e48e..00000000 --- a/_todo/programme/odbc_2.py +++ /dev/null @@ -1,9 +0,0 @@ -import odbc -cx = odbc.odbc("mysqlperso") -cur = cx.cursor() - -cur.execute ("""INSERT INTO ELEVE (num, nom, prenom, date, adresse, codepays, classe) - VALUES (1, 'dupre', 'xavier', '1975-08-11', '---- paris', 33, 19) ;""") -cur.execute ("""INSERT INTO ELEVE (num, nom, prenom, date, adresse, codepays, classe) - VALUES (2, 'dupre', 'gilles', '1946-12-24', '---- charleville', 33, 56) ;""") -cx.commit () \ No newline at end of file diff --git a/_todo/programme/odbc_3.py b/_todo/programme/odbc_3.py deleted file mode 100644 index 266f0560..00000000 --- a/_todo/programme/odbc_3.py +++ /dev/null @@ -1,8 +0,0 @@ -# coding: latin-1 -import odbc -cx = odbc.odbc("mysqlperso") -cur = cx.cursor() - -cur.execute ("SELECT * from ELEVE") -for row in cur.fetchall () : - print [ str (r) for r in row ] \ No newline at end of file diff --git a/_todo/programme/pi.py b/_todo/programme/pi.py deleted file mode 100644 index 261d10a5..00000000 --- a/_todo/programme/pi.py +++ /dev/null @@ -1,14 +0,0 @@ -# coding: latin-1 -import random -import math - -somme = 0 -nb = 1000000 -for i in range (0,nb) : - x = random.random () # nombre alatoire entre [0,1] - y = random.random () - r = math.sqrt (x*x + y*y) # racine carre - if r <= 1 : somme += 1 - -print "estimation ", 4 * float (somme) / nb -print "PI = ", math.pi \ No newline at end of file diff --git a/_todo/programme/rawinput.py b/_todo/programme/rawinput.py deleted file mode 100644 index 7b63f5bb..00000000 --- a/_todo/programme/rawinput.py +++ /dev/null @@ -1,16 +0,0 @@ -import Tkinter -def question (legende) : - reponse = [""] - root = Tkinter.Tk () - root.title ("pseudo raw_input") - Tkinter.Label (text = legende).pack (side = Tkinter.LEFT) - s = Tkinter.Entry (text= "def", width=80) - s.pack (side = Tkinter.LEFT) - def rget () : - reponse [0] = s.get () - root.destroy () - Tkinter.Button (text = "ok", command = rget).pack (side = Tkinter.LEFT) - root.mainloop () - return reponse [0] - -print "reponse ", question ("texte de la question") \ No newline at end of file diff --git a/_todo/programme/sample_isinstance.py b/_todo/programme/sample_isinstance.py deleted file mode 100644 index 8dc6dc6d..00000000 --- a/_todo/programme/sample_isinstance.py +++ /dev/null @@ -1,21 +0,0 @@ -def fonction_somme_list (ens) : - r = "list " - for e in ens : r += e - return r - -def fonction_somme_dict (ens) : - r = "dict " - for k,v in ens.items () : r += v - return r - -def fonction_somme (ens) : - if isinstance (ens, dict) : return fonction_somme_dict (ens) - elif isinstance (ens, list) : return fonction_somme_list (ens) - else : return "erreur" - -li = ["un", "deux", "trois"] -di = {1:"un", 2:"deux", 3:"trois"} -tu = ("un", "deux", "trois") -print(fonction_somme(li)) # affiche list undeuxtrois -print(fonction_somme(di)) # affiche dict undeuxtrois -print(fonction_somme(tu)) # affiche erreur \ No newline at end of file diff --git a/_todo/programme/sample_module.cpp b/_todo/programme/sample_module.cpp deleted file mode 100644 index 9f8d593f..00000000 --- a/_todo/programme/sample_module.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -/** -Une fois importe, le module definit deux fonctions : - - exemple qui prend une chaine en argument et retourne 0 - - exemple2 qui leve une exception creee pour l'occasion -*/ - - - -static PyObject* ExempleErreur; - -static PyObject* exemple (PyObject* self, PyObject* args) -{ - const char* chaine; - - if (!PyArg_ParseTuple (args, "s", &chaine)) - return NULL; - - return Py_BuildValue("i", 2); -} - -static PyObject* exemple2(PyObject* self, PyObject* args) -{ - //const char* chaine ; - - PyErr_SetString (ExempleErreur, "Exemple de leve d'erreur") ; - return NULL; -} - -//////////////////////////////////////////////////// -//////////// export des fonctions ////////////////// -//////////////////////////////////////////////////// - -const char * module_name = "sample_module" ; -char buffer [100] ; - -static PyMethodDef fonctions [] = { - {"exemple", exemple, METH_VARARGS, "Un commentaire"}, - {"exemple2", exemple2, METH_VARARGS, "Une methode levant une exception"}, - {NULL, NULL, 0, NULL} -} ; - -PyMODINIT_FUNC initsample_module(void) -{ - PyObject* m ; - m = Py_InitModule (module_name, fonctions) ; - - - sprintf (buffer, "%s.Exception", module_name) ; - ExempleErreur = PyErr_NewException(buffer, NULL, NULL) ; - Py_INCREF (ExempleErreur) ; - PyModule_AddObject (m, "Exception", ExempleErreur) ; -} diff --git a/_todo/programme/selection_file.py b/_todo/programme/selection_file.py deleted file mode 100644 index 62f2e9ef..00000000 --- a/_todo/programme/selection_file.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -"""module contenant une boîte de dialogue permettant -de sélectionner un fichier ou un répertoire, -il utilise l'interface Tkinter""" -import tkinter -import os.path -import os - -class FileSelection(object) : - """classe permettant de sélectionner un fichier - ou un répertoire à travers une boîte de dialogue""" - - def __init__(self, parent, titre = "Sélection de fichier", \ - chemin = None, file = True, exist= True) : - """ - initialise la classe - - @param parent parent - @param titre titre de la fenêtre - @param chemin fichier ou répertoire par défaut - @param file True : fichier, False : répertoire - @param exist True : le répertoire ou le fichier - sélectionné doit exister""" - self.parent = parent - self.titre = titre - self.chemin = chemin - self.file = file - self.exist = exist - - if self.chemin is None: - self.chemin = os.getcwd() - - def get_list(self) : - """retourne la liste des fichiers et des répertoires(2 listes), - répertoires seulement et [] si self.file == False""" - if os.path.isdir(self.chemin): - listf = os.listdir(self.chemin) - else : - ch, fi = os.path.split(self.chemin) - listf = os.listdir(ch) - - lifile = [] - lidir = [] - for l in listf: - if os.path.isdir(self.chemin + "\\" + l) : - lidir.append(l) - elif self.file: - lifile.append(l) - - lidir.sort() - lifile.sort() - return lidir, lifile - - def run(self) : - """lance la boîte de dialogue et retourne la chaîne sélectionnée""" - if self.parent is None: - top = tkinter.Toplevel() - top.wm_title(self.titre) - else: - top = self.parent - self.resultat = False - - fli = tkinter.Frame(top) - scrollbar = tkinter.Scrollbar(fli) - li = tkinter.Listbox(fli, width = 120, height = 15, \ - yscrollcommand = scrollbar.set) - scrollbar.config(command = li.yview) - ch = tkinter.Entry(top, width = 120) - f = tkinter.Frame(top) - prec = tkinter.Button(f, text = "Précédent") - suiv = tkinter.Button(f, text = "Entre") - annul = tkinter.Button(f, text = "Annuler") - ok = tkinter.Button(f, text = "Ok") - - prec.grid(column = 0, row = 0) - suiv.grid(column = 1, row = 0) - annul.grid(column = 3, row = 0) - ok.grid(column = 4, row = 0) - li.pack(side = tkinter.LEFT) - scrollbar.pack(side = tkinter.RIGHT, fill = tkinter.Y) - fli.pack() - ch.pack() - f.pack() - - def update_chemin() : - """mise à jour du chemin dans la boîte de dialogue""" - s = ch.get() - ch.delete(0, len(s)) - ch.insert(0, self.chemin) - - def update_list() : - """mise à jour de la liste des fichiers et répertoires - à partir de la chaîne dans la boîte de dialogue""" - self.chemin = ch.get() - lidir, lifile = self.get_list() - li.delete(0, tkinter.END) - if len(lidir) > 0 : - for l in lidir: - li.insert(tkinter.END, "+ "+ l) - if len(lifile) > 0: - for l in lifile: - li.insert(tkinter.END, " "+ l) - - def precedent() : - """passe au répertoire précédent""" - if os.path.isdir(self.chemin) : - ch, last = os.path.split(self.chemin) - self.chemin = ch - else : - ch, last = os.path.split(self.chemin) - ch, last = os.path.split(ch) - self.chemin = ch - update_chemin() - update_list() - - def suivant() : - """rentre dans un répertoire""" - sel = ch.get() - if os.path.isdir(sel) : - self.chemin = sel - update_chemin() - update_list() - - def update_sel() : - """mise à jour de la chaîne de caractères - dans la boîte de dialogue à partir de la ligne - sélectionnée dans la liste""" - li.after(200, update_sel) - sel = li.curselection() - if len(sel) == 1 : - t = li.get(sel [0]) - c = self.chemin + "\\" + t [2:len(t)] - s = ch.get() - ch.delete(0, len(s)) - ch.insert(0, c) - - def annuler() : - """annule la recherche""" - self.resultat = False - top.destroy() - top.quit() - - def accepter() : - """accepte le résultat""" - self.resultat = True - self.chemin = ch.get() - top.destroy() - top.quit() - - prec.config(command = precedent) - suiv.config(command = suivant) - annul.config(command = annuler) - ok.config(command = accepter) - - update_chemin() - update_list() - update_sel() - ch.focus_set() - - if self.parent is None: - top.mainloop() - - -if __name__ == "__main__" : - - def run(root) : - r = FileSelection(root, "sélection d'un fichier", "c:\\") - s = r.run() - return r - - root = tkinter.Tk() - win = run(root) - root.mainloop() - print("fichier sélectionné ", win.chemin) diff --git a/_todo/programme/selection_file_print.py b/_todo/programme/selection_file_print.py deleted file mode 100644 index 39d6956f..00000000 --- a/_todo/programme/selection_file_print.py +++ /dev/null @@ -1,131 +0,0 @@ -# coding: latin-1 -"""module permettant de slection un fichier, -fonctionne sans interface graphique""" -import os.path -import os - -class FileSelection (object) : - """classe permettant de slectionner un fichier - sans bote de dialogue""" - - def __init__ (self, titre = "Slection de fichier", \ - chemin = None, file = True, exist= True) : - """initialise la classe - @param titre titre de la fentre - @param chemin fichier ou rpertoire par dfaut - @param file True : fichier, False : rpertoire - @param exist True : le rpertoire ou le fichier - slectionn doit exister""" - self.titre = titre - self.chemin = chemin - self.file = file - self.exist = exist - - if self.chemin == None : self.chemin = os.getcwd () - - def get_list (self) : - """retourne la liste des fichiers et des rpertoires (2 listes), - rpertoires seulement et [] si self.file == False""" - if os.path.isdir (self.chemin) : - list = os.listdir (self.chemin) - else : - ch,fi = os.path.split (self.chemin) - list = os.listdir (ch) - - lifile = [] - lidir = [] - for l in list : - if os.path.isdir (self.chemin + "\\" + l) : - lidir.append (l) - elif self.file : - lifile.append (l) - - lidir.sort () - lifile.sort () - return lidir, lifile - - def run (self) : - """lance la slection d'un fichier""" - - def update_chemin () : - """mise jour du chemin dans la bote de dialogue""" - pass - - def update_list () : - """mise jour de la liste des fichiers et rpertoires - partir de la chane dans la bote de dialogue""" - lidir, lifile = self.get_list () - print " rpertoires" - for l in lidir : print " ", l - print " fichiers" - for l in lifile : print " ", l - - def precedent () : - """passe au rpertoire prcdent""" - if os.path.isdir (self.chemin) : - ch, last = os.path.split (self.chemin) - self.chemin = ch - else : - ch, last = os.path.split (self.chemin) - ch, last = os.path.split (ch) - self.chemin = ch - #update_chemin () - #update_list () - - def suivant (sel) : - """rentre dans un rpertoire""" - sel2 = self.chemin + "\\" + sel - if os.path.isdir (sel2) : - self.chemin = sel2 - #update_chemin () - #update_list () - - def update_sel () : - """mise jour de la chane de caractres - dans la bote de dialogue partir de la ligne - slectionne dans la liste""" - pass - - def annuler () : - """annule la recherche""" - self.resultat = False - - def accepter () : - """accepte le rsultat""" - self.resultat = True - - while True : - print "chemin actuel : ", self.chemin - print "liste des fichiers et rpertoire inclus" - update_list () - print "quelle action : Prcdent, Entre, Annuler, " \ - "Ok (entrer la lettre majuscule)\n" - str = raw_input ("") - if str == "P" : - precedent () - elif str == "E" : - sel = raw_input ("entrer un nom de rpertoire\n") - suivant (sel) - elif str == "A" : - annuler () - break # on sort de la boucle - elif str == "O" : - print "Entrer un nom de fichier" - str = raw_input ("\n") - self.chemin += "\\" + str - accepter () - break # on sort de la boucle - else : - print "choix incomprhensible" - print "--------------------------------------------" - - if self.resultat : return self.chemin - else : return None - - -if __name__ == "__main__" : - r = FileSelection ("slection d'un fichier", "c:\\") - s = r.run () - print "fichier slectionn ", s - - \ No newline at end of file diff --git a/_todo/programme/selection_file_tix.py b/_todo/programme/selection_file_tix.py deleted file mode 100644 index afc94bd6..00000000 --- a/_todo/programme/selection_file_tix.py +++ /dev/null @@ -1,14 +0,0 @@ -import tkinter.tix as tix -root = tix.Tk () - -o = tix.FileSelectBox (root) -o.pack () - -def print_file () : - print(o.cget ("value")) - -b = tix.Button (root, text = "print") -b.config (command = print_file) -b.pack () - -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/setup.py b/_todo/programme/setup.py deleted file mode 100644 index de5cc9bf..00000000 --- a/_todo/programme/setup.py +++ /dev/null @@ -1,52 +0,0 @@ -# coding: windows-1251 -__rev_id__ = """setup.py,v 1.0 16/03/2008""" - -import sys -from distutils.core import setup - -DESCRIPTION = 'Python Sample' - -LONG_DESCRIPTION = \ -"This project is a skeleton for a Python library written in C++ under Windows." - -CLASSIFIERS = \ -[ - 'Operating System :: Win32', - 'Programming Language :: C++', - 'License :: none', - 'Development Status :: 0.1', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Python :: Sample' -] - -KEYWORDS = 'Python Sample' - -setup(name = 'PythonSample', - version = '0.1', - author = 'Xavier Dupr', - author_email = 'webmaster@site.com', - url = 'http://www.xavierdupre.fr/', - download_url='http://www.xavierdupre.fr/', - description = DESCRIPTION, - long_description = LONG_DESCRIPTION, - license = 'GNU 2.0', - platforms = 'Win 32', - packages = ['PythonSample'], - keywords = KEYWORDS, - classifiers = CLASSIFIERS - ) - -import distutils.sysconfig as SH -to = SH.get_python_lib () + "/PythonSample" -fr = "PythonSample" - -# pour copier des fichiers supplmentaires lors de l'installation -# python setup.py install -import shutil -import os -li = os.listdir (fr) -for f in li : - if ".dll" in f or ".exe" in f or ".chm" in f : - print "copy of file ", f - shutil.copy (fr + "/" + f, to + "/" + f) \ No newline at end of file diff --git a/_todo/programme/sql_1.py b/_todo/programme/sql_1.py deleted file mode 100644 index 825cdb46..00000000 --- a/_todo/programme/sql_1.py +++ /dev/null @@ -1,14 +0,0 @@ -import sqlite3 as SQL -cx = SQL.connect("madatabase.db3") -cur = cx.cursor() - -cur.execute (""" -CREATE TABLE ELEVE ( - num integer primary key, - nom varchar (30), - prenom varchar (30), - date date, - adresse varchar (100), - codepays integer, - classe integer) -""") \ No newline at end of file diff --git a/_todo/programme/sql_2.py b/_todo/programme/sql_2.py deleted file mode 100644 index f898e47c..00000000 --- a/_todo/programme/sql_2.py +++ /dev/null @@ -1,9 +0,0 @@ -import sqlite3 as SQL -cx = SQL.connect("madatabase.db3") -cur = cx.cursor() - -cur.execute ("""INSERT INTO ELEVE (nom, prenom, date, adresse, codepays, classe) - VALUES ('dupre', 'xavier', '11/08/1975', '---- paris', 33, 19) ;""") -cur.execute ("""INSERT INTO ELEVE (nom, prenom, date, adresse, codepays, classe) - VALUES ('dupre', 'gilles', '24/12/1946', '---- charleville', 33, 56) ;""") -cx.commit () \ No newline at end of file diff --git a/_todo/programme/sql_3.py b/_todo/programme/sql_3.py deleted file mode 100644 index 666fa19d..00000000 --- a/_todo/programme/sql_3.py +++ /dev/null @@ -1,63 +0,0 @@ -# coding: latin-1 -import sqlite3 as SQL -cx = SQL.connect("madatabase.db3") -cur = cx.cursor() - -if False : - #cur.execute ("INSERT INTO PAYS (codepays, pays) VALUES (33, 'France')") - #cur.execute ("INSERT INTO PAYS (codepays, pays) VALUES (44, 'Royaume-Uni')") - - #cur.execute ("INSERT INTO MATIERES (matiere, num) VALUES ('franais', 1)") - #cur.execute ("INSERT INTO MATIERES (matiere, num) VALUES ('mathmatiques', 2)") - #cx.commit() - - if False : - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (1,1,12)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (1,1,14)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (1,2,16)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (1,2,8)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (1,2,12)") - - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (2,1,8)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (2,1,9)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (2,2,11)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (2,2,8)") - cur.execute ("INSERT INTO NOTE (nume,numm,note) VALUES (2,2,12)") - - cx.commit () - - - import sqlite3 as SQL - cx = SQL.connect("madatabase.db3") - cur = cx.cursor() - cur.execute("select * from NOTE") - l = [] - for row in cur.fetchall(): - l.append (row) - print row - print l - -print "-------------" -cur.execute ("select * from ELEVE") -for row in cur.fetchall(): print row - -print "-------------" -req = """ -SELECT nom,prenom,AVG(note) FROM ELEVE,NOTE -WHERE num = nume and - numm IN ( SELECT num FROM MATIERES WHERE matiere = 'franais' ) -GROUP BY nume -""" -cur.execute (req) -for row in cur.fetchall(): print row - -print "-------------" -req = """ -SELECT nom,prenom,AVG(note) FROM ELEVE,NOTE -WHERE num = nume and - numm IN ( SELECT num FROM MATIERES WHERE matiere = 'franais' ) -GROUP BY nume -HAVING AVG(note) >= 10 -""" -cur.execute (req) -for row in cur.fetchall(): print row diff --git a/_todo/programme/synchro.py b/_todo/programme/synchro.py deleted file mode 100644 index 114debcc..00000000 --- a/_todo/programme/synchro.py +++ /dev/null @@ -1,16 +0,0 @@ -# coding: latin-1 -import glob -import shutil -def copie_repertoire (rep1, rep2) : - """copie tous les fichiers d'un rpertoire rep1 vers un autre rep2""" - li = glob.glob (rep1 + "/*.*") - for l in li : - to = l.replace (rep1, rep2) # nom du fichier copi - # (on remplace rep1 par rep2) - shutil.copy (l, to) - -import sys - # sys.argv [0] --> nom du programme (ici, synchro.py) -rep1 = sys.argv [1] # rcupration du premier paramtre -rep2 = sys.argv [2] # rcupration du second paramtre -copie_repertoire (rep1, rep2) \ No newline at end of file diff --git a/_todo/programme/test_pickle.py b/_todo/programme/test_pickle.py deleted file mode 100644 index 03ed7c6b..00000000 --- a/_todo/programme/test_pickle.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -import pickle -import copy - -class Test : - def __init__ (self) : - self.chaine = "a" - self.entier = 5 - self.tuple = { "h":1, 5:"j" } - - def __str__(self): - return "c='{0}' e={1} t={2}".format(self.chaine, self.entier, self.tuple) - -t = Test () - -f = open('data.bin', 'wb') # lecture -pickle.dump (t, f) -f.close() - -f = open('data.bin', 'rb') # criture -t = pickle.load (f) -f.close() - -print(t) \ No newline at end of file diff --git a/_todo/programme/test_pickle2.py b/_todo/programme/test_pickle2.py deleted file mode 100644 index 5219e967..00000000 --- a/_todo/programme/test_pickle2.py +++ /dev/null @@ -1,35 +0,0 @@ -#-*- coding: utf-8 -*- -import pickle -import copy - -class Test : - def __init__ (self) : - self.x = 5 - self.y = 3 - self.calcule_norme () # attribut calcul - def calcule_norme (self) : - self.n = (self.x ** 2 + self.y ** 2) ** 0.5 - def __getstate__ (self) : - """conversion de Test en un dictionnaire""" - d = copy.copy (self.__dict__) - del d ["n"] # attribut calcul, on le sauve pas - return d - def __setstate__ (self,dic) : - """conversion d'un dictionnaire dic en Test""" - self.__dict__.update (dic) - self.calcule_norme () # attribut calcul - - def __str__(self): - return "x={0} y={1} n={2}".format(self.x, self.y, self.n) - -t = Test () - -f = open('data.bin', 'wb') # lecture -pickle.dump (t, f) -f.close() - -f = open('data.bin', 'rb') # criture -t = pickle.load (f) -f.close() - -print(t) \ No newline at end of file diff --git a/_todo/programme/testdoc1.py b/_todo/programme/testdoc1.py deleted file mode 100644 index 8cf145f9..00000000 --- a/_todo/programme/testdoc1.py +++ /dev/null @@ -1,19 +0,0 @@ -# coding: latin-1 -def addition (l1, l2): - """cette fonction additionne deux listes - >>> addition ( [], []) - [] - >>> addition ( [1,2], [3,-1]) - [4, 1] - """ - res = [] - for i in range (0, len (l1)) : - res.append ( l1 [i] + l2 [i] ) - return res - -def _test(): - import doctest - doctest.testmod() - -if __name__ == "__main__": - _test() \ No newline at end of file diff --git a/_todo/programme/testdoc2.py b/_todo/programme/testdoc2.py deleted file mode 100644 index b792185a..00000000 --- a/_todo/programme/testdoc2.py +++ /dev/null @@ -1,25 +0,0 @@ -# coding: latin-1 -def addition (l1, l2): - """cette fonction additionne deux listes - >>> addition ( [], []) - [] - >>> addition ( [1,2], [3,-1]) - [4, 1] - >>> addition ( [1], [3,-1]) - Traceback (most recent call last): - ... - Exception: listes de tailles diffrentes - """ - if len (l1) != len (l2) : - raise Exception ("listes de tailles diffrentes") - res = [] - for i in range (0, len (l1)) : - res.append ( l1 [i] + l2 [i] ) - return res - -def _test(): - import doctest - doctest.testmod() - -if __name__ == "__main__": - _test() \ No newline at end of file diff --git a/_todo/programme/testunit1.py b/_todo/programme/testunit1.py deleted file mode 100644 index a108153b..00000000 --- a/_todo/programme/testunit1.py +++ /dev/null @@ -1,9 +0,0 @@ -# coding: latin-1 -def addition (l1, l2): - """cette fonction additionne deux listes""" - if len (l1) != len (l2) : - raise Exception ("listes de tailles diffrentes") - res = [] - for i in range (0, len (l1)) : - res.append ( l1 [i] + l2 [i] ) - return res \ No newline at end of file diff --git a/_todo/programme/testunit2.py b/_todo/programme/testunit2.py deleted file mode 100644 index 13dbc224..00000000 --- a/_todo/programme/testunit2.py +++ /dev/null @@ -1,34 +0,0 @@ -# coding: latin-1 -import unittest -from testunit1 import * - -class TestCase_for_addition (unittest.TestCase): - - def test_addition_vide (self) : - """test_addition_vide : on vrifie que l'addtion de deux listes retourne une liste vide""" - assert [] == addition ( [], [] ) - - def test_addition (self) : - """test_addition : test de [1,2] + [3,-1] != [4,1]""" - l1 = [1,2] - l2 = [3,-1] - l = addition (l1, l2) - assert l [0] == 4 and l [1] == 1 - - def test_exception (self) : - """test_exception : on vrifie que l'addition - de deux listes de tailles diffrentes gnre une exception""" - l1 = [1] - l2 = [3,-1] - try : - l = addition (l1, l2) # la fonction doit lancer une exception - assert False # si elle ne le fait pas, alors le test a achou - except Exception, e : - # on vrifie que l'exception gnre n'est pas due l'instruction assert False - assert str (e.__class__ .__name__) != "AssertionError" - # on vrifie ici que le message de l'exception est celui attendu - assert str (e) == "listes de tailles diffrentes" - -if __name__ == "__main__" : - # on lance les tests - unittest.main () \ No newline at end of file diff --git a/_todo/programme/thread1.py b/_todo/programme/thread1.py deleted file mode 100644 index c3f357a1..00000000 --- a/_todo/programme/thread1.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: cp1252 -import threading, time - -class MonThread (threading.Thread) : - def __init__ (self, jusqua) : # jusqua = donnée supplémentaire - threading.Thread.__init__(self)# ne pas oublier cette ligne - # (appel au constructeur de la classe mère) - self.jusqua = jusqua # donnée supplémentaire ajoutée à la classe - - def run (self) : - for i in range (0, self.jusqua) : - print("thread ", i) - time.sleep (0.08) # attend 100 millisecondes sans rien faire - # facilite la lecture de l'affichage - -m = MonThread (10) # crée le thread -m.start () # démarre le thread, - # l'instruction est exécutée en quelques millisecondes - # quelque soit la durée du thread - -for i in range (0,10) : - print("programme ", i) - time.sleep (0.1) # attend 100 millisecondes sans rien faire - # facilite la lecture de l'affichage \ No newline at end of file diff --git a/_todo/programme/thread2.py b/_todo/programme/thread2.py deleted file mode 100644 index 2f4336ef..00000000 --- a/_todo/programme/thread2.py +++ /dev/null @@ -1,23 +0,0 @@ -# coding: cp1252 -import threading, time - -class MonThread (threading.Thread) : - def __init__ (self, jusqua, s) : - threading.Thread.__init__ (self) - self.jusqua = jusqua - self.s = s - - def run (self) : - for i in range (0, self.jusqua) : - print("thread ", self.s, " : ", i) - time.sleep (0.09) - -m = MonThread (10, "A") -m.start () - -m2 = MonThread (10, "B") # cre un second thread -m2.start () # dmarre le thread, - -for i in range (0,10) : - print("programme ", i) - time.sleep (0.1) \ No newline at end of file diff --git a/_todo/programme/thread_attente.py b/_todo/programme/thread_attente.py deleted file mode 100644 index ba260e73..00000000 --- a/_todo/programme/thread_attente.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding: latin-1 -import threading, time - -class MonThread (threading.Thread) : - def __init__ (self, jusqua) : - threading.Thread.__init__ (self) - self.jusqua = jusqua - self.etat = False # l'tat du thread est soit False ( l'arrt) - # soit True (en marche) - - def run (self) : - self.etat = True # on passe en mode marche - for i in range (0, self.jusqua) : - print("thread itration ", i) - time.sleep (0.1) - self.etat = False # on revient en mode arrt - -m = MonThread (10) # cre un thread -m.start () # dmarre le thread, - -print("dbut") - -while m.etat == False : - # on attend que le thread dmarre - time.sleep (0.1) # voir remarque ci-dessous - -while m.etat == True : - # on attend que le thread s'arrte - # il faut introduire l'instruction time.sleep pour temporiser, il n'est pas - # ncessaire de vrifier sans cesse que le thread est toujours en marche - # il suffit de le vrifier tous les 100 millisecondes - # dans le cas contraire, la machine passe son temps vrifier au lieu - # de se consacrer l'excution du thread - time.sleep (0.1) - -print("fin") \ No newline at end of file diff --git a/_todo/programme/thread_attente2.py b/_todo/programme/thread_attente2.py deleted file mode 100644 index 52298519..00000000 --- a/_todo/programme/thread_attente2.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: latin-1 -import threading, time - -class MonThread (threading.Thread) : - def __init__ (self, jusqua, event) : # event = objet Event - threading.Thread.__init__ (self) # = donne supplmentaire - self.jusqua = jusqua - self.event = event # on garde un accs l'objet Event - - def run (self) : - for i in range (0, self.jusqua) : - print("thread itration ", i) - time.sleep (0.1) - self.event.set () # on indique qu'on a fini : - # on active l'object self.event -print("dbut") - -event = threading.Event () # on cre un objet de type Event -event.clear () # on dsactive l'ojet Event -m = MonThread (10, event) # cre un thread -m.start () # dmarre le thread, -event.wait () # on attend jusqu' ce que l'objet soit activ - # event.wait (0.1) : n'attend qu'un -print("fin") # seulement 1 dizime de seconde \ No newline at end of file diff --git a/_todo/programme/thread_interface.py b/_todo/programme/thread_interface.py deleted file mode 100644 index 6a982ce2..00000000 --- a/_todo/programme/thread_interface.py +++ /dev/null @@ -1,67 +0,0 @@ -# coding: latin-1 -import threading, time, random, copy - -# dfinition du thread -class MonThread (threading.Thread) : - def __init__ (self, win, res) : - threading.Thread.__init__ (self) - self.win = win # on mmorise une rfrence sur la fentre - self.res = res - - def run (self) : - for i in range (0, 10) : - print("thread ", i) - time.sleep (0.1) - - # afin que le thread retourne un rsultat - # self.res dsigne thread_resultat qui reoit un nombre de plus - h = random.randint (0,100) - self.res.append (h) - - # on lance un vnement <> la fentre principale - # pour lui dire que le thread est fini, l'vnement est ensuite - # gr par la boucle principale de messages - # on peut transmettre galement le rsultat lors de l'envoi du message - # en utilisant un attribut de la classe Event pour son propre compte - self.win.event_generate ("<>", x = h) - -thread_resultat = [] - -def lance_thread () : - global thread_resultat - # fonction appele lors de la pression du bouton - # on change la lgnde de la zone de texte - text .config (text = "thread dmarr") - text2.config (text = "thread dmarr") - # on dsactive le bouton pour viter de lancer deux threads en mme temps - bouton.config (state = TK.DISABLED) - # on lance le thread - m = MonThread (root, thread_resultat) - m.start () - -def thread_fini_fonction (e) : - global thread_resultat - # fonction appele lorsque le thread est fini - print("la fentre sait que le thread est fini") - # on change la lgende de la zone de texte - text .config (text = "thread fini + rsultat " + str (thread_resultat)) - text2.config (text = "thread fini + rsultat (e.x) " + str (e.x)) - # on ractive le bouton de faon pouvoir lancer un autre thread - bouton.config (state = TK.NORMAL) - -import tkinter as TK - -# on cre la fentre -root = TK.Tk () -bouton = TK.Button (root, text = "thread dpart", command = lance_thread) -text = TK.Label (root, text = "rien") -text2 = TK.Label (root, text = "rien") -bouton.pack () -text.pack () -text2.pack () - -# on associe une fonction un vnement <> propre au programme -root.bind ("<>", thread_fini_fonction) - -# on active la boucle principale de message -root.mainloop () \ No newline at end of file diff --git a/_todo/programme/thread_partage.py b/_todo/programme/thread_partage.py deleted file mode 100644 index d59b1ba7..00000000 --- a/_todo/programme/thread_partage.py +++ /dev/null @@ -1,47 +0,0 @@ -# coding: latin-1 -import threading, time - -message = "" -verrou = threading.Lock () - -def ajoute (c) : - global message # message et verrou sont des variables gloables - global verrou # pour ne pas qu'elle disparaisse ds la fin de la fonction - #verrou.acquire () # on protge ce qui suit (*) - - s = message + c # instructions jamais excute simultanment par 2 threads - time.sleep (0.001) # time.sleep : pour exagrer le dfaut de synchronisation - message = s # si verrou n'est pas utilis - - #verrou.release () # on quitte la section protge (*) - -class MonThread (threading.Thread) : - def __init__ (self, jusqua, event, s) : - threading.Thread.__init__ (self) - self.jusqua = jusqua - self.s = s - self.event = event - - def run (self) : - for i in range (0, self.jusqua) : - ajoute (self.s) - self.event.set () - -print("dbut") - -# synchronisation attente -e1 = threading.Event () -e2 = threading.Event () -e1.clear () -e2.clear () - -m1 = MonThread (10, e1, "1") # cre un thread -m1.start () # dmarre le thread, -m2 = MonThread (10, e2, "2") # cre un second thread -m2.start () # dmarre le second thread, - -e1.wait () -e2.wait () - -print("longueur ", len(message)) # affiche 20 -print("message = ", message) # affiche quelque chose comme 12212112211212121221 diff --git a/_todo/programme/threadqueue.py b/_todo/programme/threadqueue.py deleted file mode 100644 index 69d91f8d..00000000 --- a/_todo/programme/threadqueue.py +++ /dev/null @@ -1,91 +0,0 @@ -# coding: latin-1 -import threading, time, queue, random - -class Joueur (threading.Thread) : - - # initialisation - def __init__ (self, nom, e, nb = 1000, temps = 0.1) : - threading.Thread.__init__(self) - self.nb = nb - self.queue = queue.Queue () - self.nom = nom - self.event = e - self.temps = temps # temps de rflexion - def Joueur (self, autre_joueur) : self.autre = autre_joueur - - # mthodes : l'adversaire m'envoie un message - def Joue (self, nombre) : self.queue.put_nowait ( ("essai", nombre) ) - def Dessus (self, nombre) : self.queue.put_nowait ( ("dessus", nombre) ) - def Dessous (self, nombre) : self.queue.put_nowait ( ("dessous", nombre) ) - def Gagne (self, nombre) : - while not self.queue.empty () : - try :self.queue.get () - except : pass - self.queue.put ( ("gagne", nombre) ) - - # je joue - def run (self) : - x = random.randint (0,self.nb) - print(self.nom, " : je joue (", x, ")") - i = 0 - a = 0 - b = self.nb - while True : - time.sleep (self.temps) - - try : - m,n = self.queue.get_nowait () # dsynchronis - #m,n = self.queue.get (timeout = 0.5)# l'un aprs l'autre - except queue.Empty: - m,n = None,None - - # traitement du message --> rponse l'adversaire - if m == "essai" : - if n == x : - self.autre.Gagne (n) - print(self.nom, " : j'ai perdu aprs ", i, " essais") - break - elif n < x : self.autre.Dessus (n) - else : self.autre.Dessous (n) - elif m == "dessus" : - a = max (a, n+1) - continue # assure l'quit en mode l'un aprs l'autre - elif m == "dessous" : - b = min (b, n-1) - continue # assure l'quit en mode l'un aprs l'autre - elif m == "gagne" : - print(self.nom, " : j'ai gagn en ", i, " essais, solution ", n) - break - - # on fait une tentative - if a == b : n = a - else : n = random.randint (a,b) - self.autre.Joue (n) - i += 1 - print(self.nom, " : je tente ", n, " cart ", b-a, " traiter ", self.queue.qsize ()) - - # fini - print(self.nom, " : j'arrte") - self.event.set () - -# on cre des verrous pour attendre la fin de la partie -e1 = threading.Event () -e2 = threading.Event () -e1.clear () -e2.clear () - -# cration des joueurs -A = Joueur ("A", e1, 10, temps = 0.1) -B = Joueur ("B", e2, 10, temps = 0.3) - -# chaque joueur sait qui est l'autre -A.Joueur (B) -B.Joueur (A) - -# le jeu commence -A.start () -B.start () - -# on attend la fin de la partie -e1.wait () -e2.wait () \ No newline at end of file diff --git a/_todo/programme/toplevel_ex.py b/_todo/programme/toplevel_ex.py deleted file mode 100644 index a1c0227c..00000000 --- a/_todo/programme/toplevel_ex.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -import tkinter - -class nouvelle_fenetre : - resultat = [] - def top (self) : - sec = tkinter.Toplevel () - tkinter.Label (sec, text="entrer quelque chose").pack () - saisie = tkinter.Entry (sec) - saisie.pack() - tkinter.Button (sec, text = "valider", command = sec.quit).pack () - sec.mainloop () - nouvelle_fenetre.resultat.append ( saisie.get () ) - sec.destroy () - -root = tkinter.Tk() #fenetre principale -a = tkinter.Button (text = "fenêtre Toplevel", - command = nouvelle_fenetre ().top) -a.pack() -root.mainloop() - -for a in nouvelle_fenetre.resultat : - print("contenu ", a) \ No newline at end of file diff --git a/_todo/programme/tri_position.py b/_todo/programme/tri_position.py deleted file mode 100644 index 34a99337..00000000 --- a/_todo/programme/tri_position.py +++ /dev/null @@ -1,4 +0,0 @@ -tab = ["zro", "un", "deux"] # tableau trier -pos = [ (tab [i],i) for i in range (0, len (tab)) ] # tableau de couples -pos.sort () # tri -print pos # affiche [('deux', 2), ('un', 1), ('zro', 0)] \ No newline at end of file diff --git a/_todo/programme/unuunicode.py b/_todo/programme/unuunicode.py deleted file mode 100644 index a2b1e927..00000000 --- a/_todo/programme/unuunicode.py +++ /dev/null @@ -1,7 +0,0 @@ -# coding: latin-1 -st = "e" -su = u"e" # raccourci pour su = unicode ("e", "latin-1") -print len (st), ";", st # affiche 2 ; e -print len (repr (st)), ";", repr (st) # affiche 7 ; 'e\xe9' -print len (su), ";", su.encode ("latin-1") # affiche 2 ; e -print len (repr (su)), ";", repr (su) # affiche 8 ; u'e\xe9' diff --git a/_todo/programme/unuunicode2.py b/_todo/programme/unuunicode2.py deleted file mode 100644 index 30748221..00000000 --- a/_todo/programme/unuunicode2.py +++ /dev/null @@ -1,8 +0,0 @@ -# coding: utf-8 -s = unicode ("t".decode ("utf-8")) -print len (s), s.encode ("utf-8") -print len (repr (s)), repr (s) - -s = u"ete" -print len (s), s -print len (repr (s)), repr (s) diff --git a/_todo/programme/zip_sample.py b/_todo/programme/zip_sample.py deleted file mode 100644 index 13374f09..00000000 --- a/_todo/programme/zip_sample.py +++ /dev/null @@ -1,4 +0,0 @@ -import glob -import os - -print os.listdir ("c:\\temp\\*") diff --git a/_todo/python_cours_biblio.tex b/_todo/python_cours_biblio.tex deleted file mode 100644 index 47db38e3..00000000 --- a/_todo/python_cours_biblio.tex +++ /dev/null @@ -1,90 +0,0 @@ -% insre une entre dans la bibliographie -% 1 - identifiant -% 2 - anne -% 3 - auteurs -% 4 - titre -% 5 - revue -% 6 - volume -% 7 - page dbut -% 8 - page fin - -\bibitemstyle{Bailly2008}{2008} {Yves Bailly} -{Initiation la programmation avec Python et C++} -{Editions Le programmeur}{}{0}{} - -\bibitemstyle{Brucher2008}{2008} {Matthieu Brucher} -{Les Fondamentaux du langage - La Programmation pour les scientifiques} -{Editions ENI}{}{0}{} - -\bibitemstyle{Dayley2007}{2007} {Brad Dayley} -{Python - L'essentiel du code et des commandes} -{Pearson}{}{0}{} - -\bibitemstyle{Dupr2011}{2011} {Xavier Dupr} -{Programmation avec le Langage Python Deuxime Edition} -{Ellipse}{}{0}{} - -\bibitemstyle{McKinney2012}{2012} {Wes McKinney} -{Python for Data Analysis} -{O'Reilly}{}{0}{} - -\bibitemstyle{Pilgrim2011}{2011} {Mark Pilgrim} -{Dive Into Python 3, voir l'adresse \httpstyle{http://getpython3.com/diveintopython3/}, titre franais \textit{Plongez au coeur de Python}} -{APress}{}{0}{} - -\bibitemstyle{Swinnen2012}{2012} {Grard Swinnen} -{Apprendre programmer avec Python 3, voir l'adresse \httpstyle{http://www.cifen.ulg.ac.be/inforef/swi/python.htm}} -{O'Reilly, dition franaise}{}{0}{} - -\bibitemstyle{Ziad2011}{2011} {Triak Ziad, Stefan Richter} -{Programmation Python : Conception et optimisation} -{Eyrolles}{}{0}{} - - - -\if 0 -\bibitemstyle{www-DocF}{2004} {} -{documents rdigs en langue franaise} -{http://www.developpez.com/cours/}{}{0}{} - -\bibitemstyle{www-GPL}{2004} {} -{site officiel de la licence GPL} -{http://www.gnu.org/copyleft/gpl.html}{}{0}{} - -\bibitemstyle{www-Python}{2004} {} -{site officiel du langage Python} -{http://www.python.org}{}{0}{} - -\bibitemstyle{www-PyDoc}{2004} {} -{site officiel du langage Python, documentation} -{http://docs.python.org/download.html}{}{0}{} - -\bibitemstyle{www-PyEdit}{2004} {} -{diteurs de texte pour le langage Python} -{http://www.python.org/cgi-bin/moinmoin/PythonEditors}{}{0}{} - -\bibitemstyle{www-PyDownload}{2004} {} -{site officiel du langage Python, tlchargement du programma d'installation} -{http://www.python.org/download/}{}{0}{} - -\bibitemstyle{www-PyLicence}{2004} {} -{site officiel du langage Python, licence} -{http://www.python.org/psf/license.html}{}{0}{} - -\bibitemstyle{www-PyModule}{2004} {} -{site officiel du langage Python, liste des modules existant} -{http://www.python.org/pypi}{}{0}{} - -\bibitemstyle{www-Scite}{2004} {} -{diteur de texte Scite} -{http://www.scintilla.org/SciTE.html}{}{0}{} - -\bibitemstyle{www-SciteDownload}{2004} {} -{diteur de texte Scite, page de tlchargement} -{http://scintilla.sourceforge.net/SciTEDownload.html}{}{0}{} - -\bibitemstyle{www-Syn}{2004} {} -{diteur de texte Syn Text Editor} -{http://syn.sourceforge.net/}{}{0}{} - -\fi diff --git a/_todo/python_cours_titre.tex b/_todo/python_cours_titre.tex deleted file mode 100644 index e89ec1ca..00000000 --- a/_todo/python_cours_titre.tex +++ /dev/null @@ -1,12 +0,0 @@ -%---------------------------------------------------------------------------------------------------------------------- -% titre -%---------------------------------------------------------------------------------------------------------------------- - -\title{ $ $ \\ $ $ \\ $ $ \\ ENSAE \\ $ $ \\ Ecole Nationale de la Statistique et de l'Administration Economique \\$ $ \\$ $ \\$ $ \\$ $ \\$ $ \\$ $ \\ Initiation la programmation \\ $ $ \\ -avec le langage \textit{Python} \\ $ $ \\ $ $ \\ $ $ \\ $ $ \\$ $ \\$ $ \\$ $ \\ Xavier Dupr \\ $ $ \\ http://www.xavierdupre.fr/ $ $ \\ $ $ \\ $ $ \\ $ $ \\$ $ \\$ $ \\$ $ \\} -\author{Xavier Dupr} \maketitle - - -\newpage - - diff --git a/_todo/resume_utile.tex b/_todo/resume_utile.tex deleted file mode 100644 index 4ba9a702..00000000 --- a/_todo/resume_utile.tex +++ /dev/null @@ -1,1492 +0,0 @@ - -\input{../../common/paper_begin.tex}% - -\firstpassagedo{ -\title{Rsum de la syntaxe Python} -\author{Xavier Dupr \\ \httpstyle{http://www.xavierdupre.fr/}} -\maketitle -\begin{abstract} -\noindent Ce document rsume en quelques pages les lments essentiels de la syntaxe du langage \python, variables, boucles, test, fonctions. -\end{abstract} -%\shorttableofcontents{Table des matires}{2} -\setcounter{tocdepth}{1} -\tableofcontents -\hypersetup{ - pdftitle={Rsum de la syntaxe Python} - pdfauthor={Xavier Dupr} - pdfsubject={Rsum de la syntaxe Python} - pdfkeywords={Python rsum} -} -} - - - -Ce document rsume en quelques pages les lments essentiels de la syntaxe du langage \python. L'installation est simple. Le langage est prsent sur les ordinateurs Mac et Linux. Sur Windows, il suffit de l'installer avec un installateur comme la plupart des programmes. Il suffit de faire attention la version installe sur ces les lignes suivantes permettront de dcouvrir~: - -\begin{verbatimx} -import sys -print (sys.version) -\end{verbatimx} - -Tous les modules additionnels (\codes{numpy}, \codes{matplotlib}, ...) doivent tre installs pour cette version. Avec la version~3.x, le langage a introduit quelques changements importants qui seront signals. - - -\section{Le langage} - -Quelques rappels sur le langage~: - -\begin{enumerate} -\item Il n'y a pas de sparateur d'instructions, il faut crire une instruction par ligne et dcaler les lignes dans une boucle, un test, une fonction, une classe. Pour crire une instruction sur plusieurs lignes, il faut utiliser le caractres \codes{\backslash} sur toutes les lignes de l'instruction sauf la dernire. Il ne doit rien y avoir derrire ce caractre, ni espace, ni commentaires. Cette rgle n'est ncessaire s'il s'agit d'une liste d'lments spars par des virgules. -\item On peut mettre autant d'espaces qu'on veut. Il peut n'y en avoir aucun sauf derrire une instruction \codes{for}, \codes{if}, ... -\item Les commentaires dans un programme commencent par le symbole \codes{\#} et vont jusqu' la fin de la ligne. -\item L'instruction \codes{print} permet d'afficher n'importe quelle information. Elle affiche le rsultat de la mthode \codes{\_\_str\_\_} pour les classes. \textbf{Version~3.x:} \codes{print} est une fonction, tout ce qui doit tre affich doit l'tre entre parenthses. -\item L'instruction \codes{help} affiche l'aide associe une variable, une fonction, une classe, une mthode, un module. Pour une fonction, une classe, une mthode du programme, cette aide correspond une chane de caractres encadre par trois ". Ce message d'aide peut s'taler sur plusieurs lignes. -\begin{verbatimx} -def fonction () : - """fonction de - dmonstration""" - return 0 -help (fonction) # affiche fonction de - # dmonstration -\end{verbatimx} -\end{enumerate} - - -\textbf{2 astuces en cas de problme} - -En cas de doute sur une partie de code, un calcul, une priorit entre oprateurs, le rsultat d'une fonction, il est possible d'utiliser la fonction \codes{print} pour afficher une valeur intermdiaire pendant un calcul. Il ne faut pas non plus hsiter vrifier sur un petit exemple dans un petit programme que des lignes douteuses font exactement ce pour quoi elles ont t crites. - -Il est souvent utile de chercher sur Internet des exemples de programmes pour corriger une syntaxe incorrecte, utiliser Google en ajoutant une requte commenant par le mot \python. Pour les erreurs, il est parfois intressant de recopier intgralement le message d'erreur sous Google, les rponses obtenues sont souvent assez claires. - - - -\section{Les variables} - -Le nom d'une variable commence par une lettre ou un blanc soulign, il peut galement inclure par la suite des chiffres. \pythons distingue les minuscules des majuscules. La porte d'une variable, c'est--dire la portion de code o elle dfinie, s'tend depuis sa dclaration (premire affectation) jusqu' la fin du programme ou de la fonction o elle est dfinie. Pour dclarer une variable portant le nom \codes{va}, il suffit d'crire~: -% -\begin{verbatimx} -va = -\end{verbatimx} -% -Le type de \codes{} dtermine le type de la variable \codes{va}. Si une variable de mme porte portait dj ce nom-l, son contenu est cras (perdu aussi). L'instruction \codes{type(x)} retourne le type de la variable \codes{x}. \textbf{Un identificateur ne peut tre utilis qu'une seule fois, qu'il dsigne une variable, une fonction, une classe ou un module.} - -\subsection{Les types immuables} - -Les variables de type immuable ne peuvent pas tre modifies. \indexfrr{type}{None}\indexfrr{type}{bool}\indexfrr{type}{int}\indexfrr{type}{float}\indexfrr{type}{complex}\indexfrr{type}{str}\indexfrr{type}{unicode}\indexfrr{type}{tuple} -\begin{enumerate} -\item \codes{None}, ce type veut dire rien, il est utilis comme convention de programmation pour dire qu'un algorithme, un calcul ne s'est pas termin correctement ou une valeur n'a pas encore t calcule. -\item \codes{bool} : un boolen (rsultat d'un test) -\item \codes{int} : un entier -\item \codes{float} : un rel -\item \codes{complex} : un complexe -\item \codes{str} : une chane de caractres ou string, elle apparat entre guillemets, entre apostrophes, entre trois guillements (""") si elle s'tend sur plusieurs lignes. \codes{s = "exemple"}. \textbf{Version 2.7~:} il existe un autre type \codes{unicode} utilis pour reprsenter des chanes de caractres non latines (en chinois par exemple). -\item \codes{tuple} : un vecteur d'lments de types identiques ou diffrents, il apparat entre parenthses, on accde un de ses lments l'aide de crochets. Les lments d'un t-uple \codes{t} sont indics de 0 \codes{len(t)-1} inclus. -\begin{verbatimx} -t = () # tuple vide -t = (2, "e") # tuple de deux lments -print (t[0]) # affiche le premier lment -\end{verbatimx} -\end{enumerate} -% -L'affectation d'une valeur de type immuable une variable est une copie. On peut appliquer sur les types numriques les oprations usuelles (+ * - / \% ** += *= -= /= \%= **=)\footnote{** est le symbole pour puissance~: \codesnote{3 ** 4} = $3^4$}. On rappelle que \codes{a += 10} est quivalent \codes{a = a + 10}, ceci signifie que la valeur de \codes{a} avant le calcul n'a plus besoin d'exister. Le \textit{et} logique et le \textit{ou} logique sont nots \codes{and} et \codes{or}. Les priorits sont celles usuellement utilises en mathmatique, en cas de doute, il faut utiliser des parenthses. - -Les oprateurs de comparaison (< > == <= >=) s'appliquent sur tous les types numriques ainsi que sur les chanes de caractres. Rappel~: les minuscules sont classes aprs les majuscules. - - -\textbf{Frquente source de bug~:} -\begin{itemize} -\item \textbf{Version 2.7~:} une division entire a pour rsultat le quotient et non un nombre dcimal. Autrement dit~: \codes{1/2 = 0} et non \codes{0.5}. -\item \textbf{Version 3.x~:} une division entire a pour rsultat un rel.Autrement dit~: \codes{1/2 = 0.5}. Pour une division entire, il faut utiliser \codes{//}~: \codes{1//2 = 0}. -\end{itemize} - -Pour convertir une information d'un type un autre, il suffit d'utiliser le nom de ce type suivi de la valeur convertir entre parenthses~: \codes{b = float ("2.145")} quivaut la conversion d'une chane de caractres en rel. - -L'addition d'un t-uple et d'une valeur retourne un t-uple incluant cette valeur la fin (plus long d'un lment). L'addition de deux t-uples concatne les deux t-uples. L'addition de deux chanes de caractres retourne leur concatnation. - -Pour savoir si un lment \codes{x} fait partie d'un t-uple \codes{t}, il faut utiliser la syntaxe \codes{x \; in \; t} dont la rciproque est \codes{x \; not \; in \; t}. - -La fonction \codes{len} retourne la longueur d'un tuple ou d'une chane de caractres. Les lments ou les caractres d'un tuple ou d'une chane de caractres \codes{t} sont indics de 0 \codes{len (t)-1} inclus. -\begin{verbatimx} -t [i:j] # correspond un sous-ensemble allant des indices i j exclu -t [:j] # = t[0:j] -t [i:] # = t [i: len (t)] -\end{verbatimx} -% -Pour les chanes de caractres, on utilise frquemment les mthodes de la table~\ref{string_method-sum}, exemple~: -% -\begin{verbatimx} -st = "langage python" -st = 'langage python' # idem -st = 'un guillement "' # chane contenant un guillement -st = "un guillement \"" # chane contenant un guillement, il faut ajouter \ - # pour ne pas confondre avec l'autre guillement -st = st.upper () # mise en lettres majuscules -i = st.find ("PYTHON") # on cherche "PYTHON" dans st -print (i) # affiche 8 Version 3.x, crire print (i), - # pour la version 2.x, crire print i -print (st.count ("PYTHON")) # affiche 1 Version 3.x : idem print (...) -print (st.count ("PYTHON", 9)) # affiche 0 Version 3.x : idem print (...) -\end{verbatimx} -% -% - \begin{table}[ht] - \begin{center}\begin{tabular}{|lp{12cm}|} \hline - \codes{count( sub[, start[, end]])} & - %\begin{minipage}{12cm} - Retourne le nombre d'occurences de la chane de caractres \codes{sub}, - les paramtres par dfaut \codes{start} et \codes{end} permettent de rduire la - recherche entre les caractres d'indice \codes{start} et \codes{end} exclu. Par dfaut, - \codes{start} est nul tandis que \codes{end} correspond la fin de la chane - de caractres. - %\end{minipage} - \\ \hline - \codes{find( sub[, start[, end]])} & - %\begin{minipage}{12cm} - Recherche une chane de caractres \codes{sub}, - les paramtres par dfaut \codes{start} et \codes{end} ont la mme signification - que ceux de la fonction \codes{count}. Cette fonction retourne -1 si - la recherche n'a pas abouti. - %\end{minipage} - \\ \hline - \codes{isalpha ()} & - %\begin{minipage}{12cm} - Retourne \codes{True} si tous les caractres sont des lettres, \codes{False} sinon. - %\end{minipage} - \\ \hline - \codes{isdigit ()} & - %\begin{minipage}{12cm} - Retourne \codes{True} si tous les caractres sont des chiffres, \codes{False} sinon. - %\end{minipage} - \\ \hline - \codes{replace( old, new[, count])} & - %\begin{minipage}{12cm} - Retourne une copie de la chane de caractres en remplaant toutes les - occurrences de la chane \codes{old} par \codes{new}. Si le paramtre optionnel - \codes{count} est renseign, alors seules les \codes{count} premires occurrences - seront remplaces. - %\end{minipage} - \\ \hline - \codes{split( [sep [,maxsplit]])} & - %\begin{minipage}{12cm} - Dcoupe la chane de caractres en se servant de la chane \codes{sep} comme - dlimiteur. Si le paramtre \codes{maxsplit} est renseign, au plus \codes{maxsplit} - coupures seront effectues. - %\end{minipage} - \\ \hline - \codes{upper ()} & Remplace les minuscules par des majuscules. \\ \hline - \codes{lower ()} & Remplace les majuscules par des minuscules. \\ \hline - \codes{join ( li )} & \codes{li} est une liste, - cette fonction agglutine tous les lments d'une liste spars par \codes{sep} - dans l'expression \codes{sep.join ( ["un", "deux"])}. \\ \hline - \end{tabular}\end{center} - \caption{ Quelques fonctions s'appliquant aux chanes de caractres, l'aide associe au langage \pythons - fournira la liste complte. Certains des paramtres sont encadrs par des crochets, - ceci signifie qu'ils sont facultatifs.\indexfrr{type}{str}} - \label{string_method-sum} - \end{table} - -L'affichage de rels ncessite parfois de tronquer la partie dcimale ce qui est fait grce la syntaxe suivante~: -% -\begin{verbatimx} -x = 0.123456789 -print ("%1.2f" % x) # donne 0.12 -s = "%2.2e %s" % (3.14159, "est une approximation de pi") -print (s) # Version 2.x : print s -\end{verbatimx} - - - - -\subsection{Les types modifiables} - -\pythons fournit deux types modifiables~: les listes et les dictionnaires. Pour ces deux types, \textbf{il faut faire attention chaque affectation}. -% -\begin{verbatimx} -a = [1,2] -b = a -\end{verbatimx} -% -La seconde ligne ne fait pas une copie de la premire liste, elle ne fait que crer un second nom pour nommer la mme liste. Pour copier une liste ou un dictionnaire, il faut utiliser~: -% -\begin{verbatimx} -a = [1,2] -import copy -b = copy.copy (a) -\end{verbatimx} -% -ou, si la liste inclut galement d'autres listes ou dictionnaires~: -% -\begin{verbatimx} -a = [1,2] -import copy -b = copy.deepcopy (a) -\end{verbatimx} -% -Cette remarque s'applique tout type modifiable, liste, dictionnaire ou tout autre classe. La suppression d'une variable n'implique pas la suppression de toutes les variables se rfrant une seule et mme instance de classe. - - -\subsubsection{Liste}\indexfrr{type}{list} - -Une liste est une sorte de tableau qui permet de mmoriser un ensemble d'lments de types varis. C'est une sorte de t-uple modifiable. La table~\ref{operation_liste_resume} regroupe les oprations qu'une liste supporte et la table~\ref{operation_liste2_resume} les mthodes dont elle dispose. -% -\begin{verbatimx} -x = [4,5] # cration d'une liste compose de deux entiers -x = ["un",1,"deux",2] # cration d'une liste compose deux chanes de caractres - # et de deux entiers, l'ordre d'criture est important -x = [3,] # cration d'une liste d'un lment, sans la virgule, - # le rsultat reste une liste -x = [ ] # cre une liste vide -x = list () # cre une liste vide -\end{verbatimx} - - - - \begin{table}[ht] - \begin{center}\begin{tabular}{|lp{12cm}|} \hline - \codes{x \; in \; s} & vrai si \codes{x} est un des lments de \codes{l} \\ \hline - \codes{x \; not \; in \; s} & rciproque de la ligne prcdente \\ \hline - \codes{l + t} & concatnation de \codes{l} et \codes{t} \\ \hline - \codes{l * n} & concatne \codes{n} copies de \codes{l} les unes la suite des autres \\ \hline - \codes{l[i]} & %\begin{minipage}{12cm} - retourne le i$^\text{me}$ lment de \codes{l}, - la diffrence des T-uples, l'instruction \codes{l [i] = "3"} - est valide, elle remplace l'lment \codes{i} par 3. - %\end{minipage} - \\ \hline - \codes{l[i:j]} & %\begin{minipage}{12cm} - retourne une liste contenant les lments de \codes{l} d'indices $i$ - $j$ exclu. Il est possible de remplacer cette sous-liste par une autre en - utilisant l'affectation \codes{ l[i:j] = l2 } o \codes{l2} - est une autre liste (ou un T-uple) de dimension diffrente ou gale. - %\end{minipage} - \\ \hline - \codes{l[i:j:k]} & %\begin{minipage}{12cm} - retourne une liste contenant les lments de \codes{l} dont les - indices sont compris entre $i$ et $j$ exclu, ces indices sont espacs de $k$~: - $i, i+k, i+2k, i+3k, ...$ Ici encore, il est possible d'crire l'affectation - suivante~: \codes{ l[i:j:k] = l2 } mais \codes{l2} doit tre une liste - (ou un T-uple) de mme dimension que \codes{ l[i:j:k]}. - %\end{minipage} - \\ \hline - \codes{len(l)} & nombre d'lments de \codes{l} \\ \hline - \codes{min(l)} & %\begin{minipage}{12cm} - plus petit lment de \codes{l}, rsultat difficile prvoir - lorsque les types des lments sont diffrents - %\end{minipage} - \\ \hline - \codes{max(l)} & %\begin{minipage}{12cm} - plus grand lment de \codes{l}, rsultat difficile prvoir - lorsque les types des lments sont diffrents - %\end{minipage} - \\ \hline - \codes{sum(l)} & %\begin{minipage}{12cm} - retourne la somme de tous les lments - %\end{minipage} - \\ \hline - \codes{del \;l [i:j]} & %\begin{minipage}{12cm} - supprime les lments d'indices entre \codes{i} et \codes{j} exclu. - Cette instruction est quivalente \codes{ l [i:j] = [] }. - %\end{minipage} - \\ \hline - \codes{list (x)} & %\begin{minipage}{12cm} - convertit \codes{x} en une liste quand cela est possible - %\end{minipage} - \\ \hline - \end{tabular}\end{center} - \caption{ Oprations disponibles sur les listes, identiques celles des T-uples, - on suppose que \codescaption{l} et \codescaption{t} sont des listes, \codescaption{i} et \codescaption{j} sont - des entiers. - \codescaption{x} est quant lui quelconque.} - \label{operation_liste_resume} - \end{table} - - - - \begin{table}[ht] - \begin{center}\begin{tabular}{|lp{12cm}|} \hline - \codes{l.count (x)} & %\begin{minipage}{12cm} - Retourne le nombre d'occurrences de l'lment \codes{x}. - \codes{count} est une mthode de la classe \codes{list}. - %\end{minipage} - \\ \hline - \codes{l.index (x)} & %\begin{minipage}{12cm} - Retourne l'indice de la premire occurrence de l'lment \codes{x} - dans la liste \codes{l}. Si celle-ci n'existe, une exception est - dclenche. \indexfr{exception} - %\end{minipage} - \\ \hline - \codes{l.append (x)} & %\begin{minipage}{12cm} - Ajoute l'lment \codes{x} la fin de la liste \codes{l}. Si \codes{x} - est une liste, cette fonction ajoute la liste \codes{x} en tant qu'lment, - au final, la liste \codes{l} ne contiendra qu'un lment de plus. - %\end{minipage} - \\ \hline - \codes{l.extend (k)} & %\begin{minipage}{12cm} - Ajoute tous les lments de la liste \codes{k} la liste \codes{l}. - La liste \codes{l} aura autant d'lments supplmentaires qu'il y en a - dans la liste \codes{k}. - %\end{minipage} - \\ \hline - \codes{l.insert(i,x)} & %\begin{minipage}{12cm} - Insre l'lment \codes{x} la position \codes{i} dans la liste \codes{l}. - %\end{minipage} - \\ \hline - \codes{l.remove (x)} & %\begin{minipage}{12cm} - Supprime la premire occurence de l'lment \codes{x} dans la liste \codes{l}. - S'il n'y a aucune occurrence de \codes{x}, cette mthode dclenche - une exception. - %\end{minipage} - \\ \hline - \codes{l.pop ([i])} & %\begin{minipage}{12cm} - Retourne l'lment \codes{l[i]} et le supprime de la liste. Le - paramtre \codes{i} est facultatif, s'il n'est pas prcis, c'est le dernier - lment dont la valeur est d'abord retourne puis il est supprim de la liste. - %\end{minipage} - \\ \hline - \codes{l.reverse (x)} & %\begin{minipage}{12cm} - Retourne la liste, le premier et dernier lment changent leurs places, - le second et l'avant dernier, et ainsi de suite. - %\end{minipage} - \\ \hline - \codes{l.sort ([f])} & %\begin{minipage}{12cm} - Cette fonction trie la liste par ordre croissant. Le paramtre \codes{f} - est facultatif, il permet de prciser la fonction de comparaison qui doit - tre utilise lors du tri. Cette fonction prend comme paramtre - deux lments \codes{x} et \codes{y} de la liste et retourne les valeurs -1,0,1 - selon que \codes{x < y}, \codes{x == y} ou \codes{x > y} - (voir paragraphe~\ref{chap_fonction}). - %\end{minipage} - \\ \hline - \end{tabular}\end{center} - \caption{ Oprations permettant de modifier une liste - on suppose que \codescaption{l} est une liste, - \codescaption{x} est quant lui quelconque.} - \label{operation_liste2_resume} - \end{table} - -Les listes peuvent aussi tre dfinies partir d'une criture abrge~: -% -\begin{verbatimx} -x = range(0,5) # liste des entiers de 0 5 exclu - # Version 3.x : range retourne un itrateur, il faut crire - # x = list(range(0,5)) -y = [ i for i in x if i % 2 == 0] # slection des lments pairs -print (y) # affiche [0,2,4] Version 2.x : crire print y -z = [ i+j for i in x for j in x] # construit tous les nombres i+j possibles -print (z) # affiche [0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, - # 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8] -\end{verbatimx} - - - -\subsubsection{Dictionnaire}\indexfrr{type}{dict} - -Un dictionnaire est un tableau pour lequel les indices ou cls ne sont pas uniquement des entiers mais tout type non modifiable (le plus souvent un entier, un rel, une chane de caractres, un t-uple). -% -\begin{verbatimx} -x = { "cle1":"valeur1", "cle2":"valeur2" } -print (x ["cle1"]) # affiche valeur1 Version 2.x : crire print ... -x [(0,1)] = "cl tuple" # ajoute une nouvelle valeur dont la cl est (0,1) - # les parenthses sont superflues -y = { } # cre un dictionnaire vide -z = dict () # cre aussi un dictionnaire vide -\end{verbatimx} -% -La table~\ref{operation_dict_resume} regroupe les oprations qu'un dictionnaire supporte. La table~\ref{operation_dict2_resume} regroupe les mthodes d'un dictionnaire. - - \begin{table}[ht] - \begin{center}\begin{tabular}{|lp{12cm}|} \hline - \codes{x \; in \; d} & vrai si \codes{x} est une des cls de \codes{d} \\ \hline - \codes{x \; not \; in \; d} & rciproque de la ligne prcdente \\ \hline - \codes{l[i]} & %\begin{minipage}{12cm} - retourne l'lment associ la cl \codes{i} - %\end{minipage} - \\ \hline - \codes{len(d)} & nombre d'lments de \codes{d} \\ \hline - \codes{min(d)} & %\begin{minipage}{12cm} - plus petite cl - %\end{minipage} - \\ \hline - \codes{max(d)} & %\begin{minipage}{12cm} - plus grande cl - %\end{minipage} - \\ \hline - \codes{del \;l [i]} & %\begin{minipage}{12cm} - supprime l'lment associ la cl \codes{i} - %\end{minipage} - \\ \hline - \codes{list (d)} & %\begin{minipage}{12cm} - retourne une liste contenant toutes les cls du dictionnaire \codes{d}. - %\end{minipage} - \\ \hline - \codes{dict (x)} & %\begin{minipage}{12cm} - convertit \codes{x} en un dictionnaire si cela est possible, - en particulier, \codes{d} est gal \codes{ dict ( d.items () ) } - %\end{minipage} - \\ \hline - \end{tabular}\end{center} - \caption{ Oprations disponibles sur les dictionnaires, \codescaption{d} est un dictionnaire, - \codescaption{x} est quant lui quelconque.} - \label{operation_dict_resume} - \end{table} - - - \begin{table}[ht] - \begin{center}\begin{tabular}{|lp{12cm}|} \hline - \codes{d.copy ()} & Retourne une copie de \codes{d}. \\ \hline - \codes{d.has\_key (x)} & Retourne \codes{True} si \codes{x} est une cl de \codes{d}. - \textbf{Version~3.x~:} la fonction n'existe plus, il faut crire \codes{x \; in \; d}. - \\ \hline - \codes{d.items ()} & %\begin{minipage}{12cm} - Retourne un itrateur parcourant contenant tous les couples (cl, valeur) - inclus dans le dictionnaire. Pour obtenir une liste, il faut crire - \codes{list ( d.items() ) }. - \textbf{Version~2.x~:} retourne une liste. - %\end{minipage} - \\ \hline - \codes{d.keys ()} & %\begin{minipage}{12cm} - Retourne un itrateur parcourant toutes les cls du dictionnaire \codes{d}. - \textbf{Version 2.x~:} retourne une liste. - %\end{minipage} - \\ \hline - \codes{d.values ()} & %\begin{minipage}{12cm} - Retourne un itrateur parcourant toutes les valeurs du dictionnaire \codes{d}. - \textbf{Version 2.x~:} retourne une liste. - %\end{minipage} - \\ \hline - \codes{d.get (k[,x])} & %\begin{minipage}{12cm} - Retourne \codes{d [k]}, si la cl \codes{k} est manquante, alors - la valeur \codes{None} est retourne moins que le paramtre optionnel \codes{x} - soit renseign, auquel cas, ce sera ce paramtre qui sera retourn. - %\end{minipage} - \\ \hline - \codes{d.clear ()} & %\begin{minipage}{12cm} - Supprime tous les lments du dictionnaire. - %\end{minipage} - \\ \hline - \codes{d.update (d2)} & %\begin{minipage}{12cm} - Pour chaque cl de \codes{d1}, \codes{d[k] = d1 [k]} - %\end{minipage} - \\ \hline - \codes{d.setdefault(k[,x])} & %\begin{minipage}{12cm} - Retourne \codes{d [k]} si la cl \codes{k} existe, sinon, affecte \codes{x} - \codes{d[k]}. - %\end{minipage} - \\ \hline - \codes{d.popitem ()} & %\begin{minipage}{12cm} - Retourne un lment et le supprime du dictionnaire. - %\end{minipage} - \\ \hline - \end{tabular}\end{center} - \caption{ Mthodes associes aux dictionnaires, \codescaption{d}, \codescaption{d2} sont des dictionnaires, - \codescaption{x} est quant lui quelconque.} - \label{operation_dict2_resume} - \end{table} - - -\subsubsection{Tableaux numriques} - -Ce type ne fait pas partie du langage \pythons standard mais il est couramment utilis. -% -\begin{verbatimx} -import numpy -a = numpy.array ( [0,1] ) -\end{verbatimx} -% -Il permet de convertir des listes en une structure plus approprie au calcul qui sont nettement plus rapides. En contrepartie, il n'est pas aussi rapide d'ajouter ou supprimer des lments. - - -\section{Tests et boucles} - -\subsection{Tests}\indexfr{test} -Les tests permettent d'excuter telle ou telle instruction selon la valeur d'une condition. Le test est suivi de \codes{:} et les instructions dpendant de ce test sont indentes (dcales vers la droite). -% -\begin{verbatimx} -if x < 5 : - x = x*2 - ... -\end{verbatimx} -% -Il peut y avoir une contrepartie~: -% -\begin{verbatimx} -if x < 5 : - x = x*2 - ... -else : - x = x*3 - ... -\end{verbatimx} -% -S'il n'y a qu'une seule instruction, elle peut s'crire en bout de ligne~: -% -\begin{verbatimx} -if x < 5 : x=x*2 -else : x=x*3 -\end{verbatimx} -% -Il peut y avoir plusieurs conditions qui s'enchanent~: -% -\begin{verbatimx} -if x < 5 : x = x*2 -elif x > 5 : x = x*3 -else : x = x*6 -\end{verbatimx} - -Il existe un raccourci pour les intervalles~: - -\begin{verbatimx} -if 5 < x and x < 10 : # peut tre crit : if 5 < x < 10 : - ... -\end{verbatimx} - -\subsection{Boucles} - -Il y a deux types de boucles, la boucle \codes{for} parcourt un ensemble, la boucle \codes{while} continue tant qu'une condition est vraie. Comme pour les tests, une boucle est suivie du syumbol \codes{:}, les lignes incluses dans cette boucle sont indentes moins qu'il n'y en ait qu'une seule, auquel cas elle peut tre crite aprs le symbole \codes{:} sur la mme ligne. \indexfrr{boucle}{while} -% -\begin{verbatimx} -while condition : - # lignes dcales - # contenu de la boucle -\end{verbatimx} -% -Quelques exemples de boucles \codes{for}~: \indexfrr{boucle}{for} -% -\begin{verbatimx} -for i in range(0,n) : # parcourt tous les entiers de 0 n-1 inclus -for i in xrange(0,n) : # mme chose mais en plus rapide - # Version 3.x : la fonction xrange n'existe plus, - # et range quivaut xrange -for i in range(n,0,-1) : # parcourt tous les entiers de n 1 inclus - # dans le sens dcroissant -for i in range(2,1000,3) : # parcourt tous les entiers de 2 1000 de 3 en 3 - # (2,5,8,...) -for e in li : # parcourt tous les lments de la liste li -for cle,valeur in di.items () : # parcourt tous les lments du dictionnaire di -\end{verbatimx} -% -Pour toutes les boucles, l'instruction \codes{break} permet de sortir de la boucle, l'instruction \codes{continue} passe directement l'itration suivante sans excuter les instructions qui suivent l'instruction \codes{continue}. - - -\subsection{Fonction \codes{enumerate}}\indexfr{enumerate} - -On peut crire~: -\begin{verbatimx} -l = [ 4, 5, 6 ] -s = 0 -for i in range(0,len(l)) : - s += l[i] -\end{verbatimx} - -Ou utiliser la fonction \codes{enumerate} qui retourne chaque lment et sa position dans l'ensemble~: -\begin{verbatimx} -l = [ 4, 5, 6 ] -s = 0 -for i,x in enumerate(l) : - s += x -\end{verbatimx} - -\subsection{Fonction \codes{zip}}\indexfr{zip} - -Pour faire la somme de deux listes terme terme, on peut crire~: -\begin{verbatimx} -l = [ 4, 5, 6 ] -g = [ 3,10,11 ] -s = 0 -for i in range(0,len(l)) : - s += l[i] + g[i] -\end{verbatimx} - -Ou utiliser la fonction \codes{zip}~: -\begin{verbatimx} -l = [ 4, 5, 6 ] -g = [ 3,10,11 ] -s = 0 -for x,y in zip(l,g) : - s += x + y -\end{verbatimx} - - - -\subsection{Fonction \codes{map}}\indexfr{map} - -Il est possible d'viter une fonction pour viter d'crire une boucle avec la fonction \codes{map}. Elle applique une fonction chaque lment d'un ensemble. - -\begin{verbatimx} -def fonction (x) : return x % 2 -li = [ 3,4,5] -li2 = map (fonction, li) -print (list(li2)) # affiche [ 1, 0, 1 ] -\end{verbatimx} - -A priori, l'ensemble qui en rsulte contient autant d'lments sauf si on utilise le mot-cl \codes{yield}.\indexfr{yield} L'exemple suivant affiche tous les nombres pairs. - -\begin{verbatimx} -def fonction (x) : - if x % 2 == 0 : yield x -li = [ 3,4,5] -li2 = map (fonction, li) -print (list(li2)) # affiche [ 4 ] -\end{verbatimx} - - -\subsection{Autres mot-cls}\indexfr{keywords}\indexfr{mot-cls} - -Le mot-cl \codes{with}\indexfr{with} est utile lorsqu'on une utilise une variable pour une portion rduite de code. Cette notation cache deux appels implicites deux mthodes comme indiqu ci-dessous. - -\begin{verbatimx} -with random_matrix(1000,1000) as mat : - # appelle mat.__enter__() - ... - # appelle mat.__exit__() -\end{verbatimx} - -Lorsque ces mthodes sont surcharges, l'utilisation de cette syntaxe rduit la taille du code. C'est le cas des fichiers (voir paragraphe~\ref{section_res_fichier}). - - -\section{Fonctions}\indexfr{fonction} - -\subsection{Dfinition, paramtres} - -Les fonctions ou sous-programmes permettent de faire la mme chose sans avoir recopier le code informatique plusieurs fois dans le programme. Elles acceptent plusieurs paramtres ou aucun, elles peuvent retourner plusieurs rsultats ou aucun. Leur dclaration suit le schma suivant~: -% -\begin{verbatimx} -def exemple_fonction (p1, p2, p3) : - # code de la fonction - return r1, r2 - -a,b = exemple_fonction (1,2,3) # exemple d'appel de la fonction -\end{verbatimx} -% -L'instruction \codes{return} n'est pas obligatoire mais si elle est prsente un ou plusieurs endroits, aucune autre instruction de la fonction ne sera excute aprs l'excution de la premire instruction \codes{return} rencontre lors de l'excution de la fonction. Les fonctions peuvent tre rcursives et inclure des paramtres par dfaut~: ces paramtres reoivent une valeur mme si celle-ci n'est pas prcise lors de l'appel. -% -\begin{verbatimx} -def exemple_fonction (p1, p2 = 4, p3 = 7) : - # code de la fonction - return r1, r2 - -a,b = exemple_fonction (1) # = exemple_fonction (1,4,7) -a,b = exemple_fonction (1,2,3) # = exemple_fonction (1,2,3) -a,b = exemple_fonction (1,2) # = exemple_fonction (1,2,7) -a,b = exemple_fonction (1,p3 = 2) # = exemple_fonction (1,4,2) -\end{verbatimx} -% -Les paramtres par dfaut doivent tous tre mis en fin de dclaration, l'exemple suivant n'est pas correct~: -% -\begin{verbatimx} -def exemple_fonction (p1, p2 = 4, p3) : - # code de la fonction - return r1, r2 -# affiche le message d'erreur : SyntaxError: non-default argument follows default argument -\end{verbatimx} -% -En ce qui concerne les paramtres, les paramtres de type non modifiable sont passs par valeur (une modification l'intrieur de la fonction n'a pas de rpercution l'extrieur). -% -\begin{verbatimx} -def exemple_fonction (p1) : - p1 = 3 -a = 1 -exemple_fonction (a) -print (a) # affiche 1 -\end{verbatimx} -% -Les paramtres de type modifiable sont passs par rfrence (une modification l'intrieur de la fonction a des rpercutions l'extrieur). -% -\begin{verbatimx} -def exemple_fonction (p1) : - p1[0] = 3 -a = [1] -exemple_fonction (a) -print (a) # affiche [3] Version 2.x : print ... -\end{verbatimx} - - -\subsection{mot-cl \codes{lambda}} - -Le mot-cl \codes{lambda} permet de dfinir des fonctions au sein d'une expression. - -\begin{verbatimx} -def fonction (x) : return x % 2 -li = [ 3,4,5] -li2 = map (fonction, li) -print (list(li2)) # affiche [ 1, 0, 1 ] -\end{verbatimx} - -Peut-tre crit comme~: - -\begin{verbatimx} -li = [ 3,4,5] -li2 = map (lambda x : x%2, li) -print (list(li2)) # affiche [ 1, 0, 1 ] -\end{verbatimx} - -Et si on veut ajouter un paramtre la fonction \codes{lambda}~: - -\begin{verbatimx} -li = [ 3,4,5] -k = 2 -li2 = map (lambda x,y=k : x%k, li) -print (list(li2)) # affiche [ 1, 0, 1 ] -\end{verbatimx} - - -\subsection{mot-cl \codes{yield}} - -La programmation fonctionnelle est de plus en plus utilise. En \python, elle se dcline sous la forme d'itrateur. - -\begin{verbatimx} -def iterate_double_on_list(l) : - for x in l : - yield x*2 -print (iterate_double_on_list( [4,5,6])) - # affiche -\end{verbatimx} - -La fonction itre sur un ensemble mais ne fait rien tant qu'on ne parcourt pas l'ensemble qu'elle gnre~: - -\begin{verbatimx} -for x in iterate_double_on_list( [4,5,6]) : - print (x) -\end{verbatimx} - -La version~3 du langage \pythons a chang des fonctions pour qu'elle retourne un itrateur sur un ensemble et non l'ensemble lui-mme. - - -\section{Classes}\indexfr{class} - -Les classes sont un moyen de dfinir de nouveaux types modifiables de variables. Peu de programmes ne les utilisent pas. Une classe est un ensemble d'attributs (ou variables) et de mthodes (ou fonctions). Un programme utilisant les classes est orient objet. Il est possible de faire les mmes choses avec ou sans classes mais leur utilisation rend d'ordinaire les grands programmes plus facile comprendre et construire. - -\subsection{Dclaration d'une classe} - -Pour dclarer une classe, on procde comme suit~: -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 - self.att2 = att2 - self.att3 = att3 - self.att4 = att1 * att2 * att3 - -a = ma_classe (-1,1,2) # dclare une variable de type ma_classe -print (a.att1) # affiche -1 -print (a.att2) # affiche 3 Version 2.x : print ... -print (a.att3) # affiche 4 -print (a.att4) # affiche -12 -\end{verbatimx} -% -Lors de la dclaration de la variable \codes{a}, le langage \pythons excute la mthode \codes{\_\_init\_\_} aussi appele constructeur. Elle permet de dfinir les attributs de la classe directement partir des paramtres ou comme le rsultat d'un calcul ou d'une fonction. Le constructeur comme toutes les autres mthodes possde comme premier paramtre \codes{self} qui permet d'accder aux attributs et aux mthodes de la classe. Le programme suivant est quivalent au premier. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 - self.att2 = att2 - self.att3 = att3 - self.att4 = self.calcule4 () - - def calcule4 (self) : - return self.att1 * self.att2 * self.att3 - -a = ma_classe (-1,1,2) # dclare une variable de type ma_classe -print (a.att1) # affiche -1 -print (a.att2) # affiche 3 -print (a.att3) # affiche 4 -print (a.att4) # affiche -12 -\end{verbatimx} - - -\subsection{Attributs et mthodes}\indexfr{attribut}\indexfr{mthode} - -Les attributs sont dclars le plus souvent l'intrieur du constructeur, plus gnralement l'intrieur de toute mthode, voire l'extrieure de la classe. Pour y faire rfrence l'intrieur d'une mthode on fait prcder le nom de l'attribut de \codes{self.}, l'extrieur de la classe, c'est le nom de l'instance suivi d'un point \codes{.} qui prcde le nom de l'attribut comme le montre le prcdent exemple. - -Une mthode est dclare l'intrieur de la classe. Elle accepte invariablement au moins un paramtre qui est \codes{self} comme dans le prcdent exemple. Les rgles d'accs sont les mmes que pour les attributs. Elles acceptent galement la rcursivit et les paramtres par dfaut l'exception du premier. Chaque instance de classe est galement munie d'un dictionnaire \codes{\_\_dict\_\_} qui recense tous les attributs. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 # attribut - self.att2 = att2 # attribut - self.att3 = att3 # attribut - self.att4 = att1 * att2 * att3 # attribut - - def calcule (self,x) : # mthode - return self.att1 * self.att2 * self.att3 * x - -a = ma_classe (1,2,3) -print (a.att1) # affiche 1 -print (a.__dict__ ["att1"]) # affiche aussi 1, ligne quivalente la prcdente -print (a.calcule(2)) # appel d'une mthode -\end{verbatimx} - - -\subsection{Mthodes statiques}\indexfr{mthode statique} - -Les mthodes statiques sont comme des fonctions~: elle ne ncessite pas d'instance d'un object pour tre appele. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - # ... - - @staticmethod - def calcule_static (x,y) : # mthode statique - return x * y - -print (ma_classe.calcule_static(2,3)) # appel d'une mthode statique -\end{verbatimx} - - - -\subsection{Oprateurs}\indexfr{oprateur} - -Les oprateurs sont des mthodes qui permettent une manipulation plus simple des objets. Leur nom est fix par convention par le langage \python, ils commencent et terminent par \codes{\_\_}. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 - self.att2 = att2 - self.att3 = att3 - self.att4 = att1 * att2 * att3 - - def __add__ (self, a) : - return ma_classe (self.att1 + a.att1, self.att2 + a.att2, \ - self.att3 + a.att3, self.att4 + a.att4) - -a = ma_classe (1,2,3) -b = ma_classe (4,5,6) -c = a + b # n'a de sens que si l'oprateur __add__ a t redfini -\end{verbatimx} -% -Il existe un oprateur spcifique pour chaque opration, cet oprateur permet de donner un sens une addition, une soustraction, ..., de deux instances d'une classe. L'oprateur \codes{\_\_str\_\_} retourne une chane de caractres et est appel par l'instruction \codes{print}. L'oprateur \codes{\_\_cmp\_\_} retourne un entier permettant des instances de la classe d'tre compares et tries par une liste. - - -\subsection{Copie d'instances}\indexfr{copie} - -Les instances de classes sont des objets modifiables, comme pour les listes, une simple affectation ne signifie pas une copie mais un second nom pour dsigner le mme objet. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 - self.att2 = att2 - self.att3 = att3 - self.att4 = att1 * att2 * att3 - -a = ma_classe (1,2,3) -b = a -b.att1 = -16 -print (a.att1) # affiche -16 -print (b.att1) # affiche -16 -\end{verbatimx} -% -Il faut donc copier explicitement l'instance pour obtenir le rsultat souhait. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 - self.att2 = att2 - self.att3 = att3 - self.att4 = att1 * att2 * att3 - -a = ma_classe (1,2,3) -import copy -b = copy.copy (a) -b.att1 = -16 -print (a.att1) # affiche 1 -print (b.att1) # affiche -16 -\end{verbatimx} - - -Lorsque une classe inclut une variable de type classe, il faut utiliser la fonction \codes{deepcopy} et non \codes{copy}. - - - -\subsection{Hritage}\indexfr{hritage} - -L'hritage est l'intrt majeur des classes et de la programmation oriente objet. Lorsqu'une classe hrite d'une autre, elle hrite de ses attributs et de ses mthodes. Le simple fait d'hriter cre donc une classe quivalente. -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1, att2, att3) : - self.att1 = att1 - self.att2 = att2 - self.att3 = att3 - self.att4 = att1 * att2 * att3 - -class ma_classe2 (ma_classe) : # hritage simple - pass # pour dire que la classe est vide -\end{verbatimx} -% -Mais hriter permet de faire deux choses : -\begin{enumerate} -\item ajouter des attributs et ajouter des mthodes -\item modifier le comportement d'une mthode existante -\end{enumerate} -% -\begin{verbatimx} -class ma_classe : - def __init__ (self, att1) : - self.att1 = att1 - self.att2 = self.calcul () - - def calcul (self) : - return self.att1 ** 2 - -class ma_classe2 (ma_classe) : - def calcul (self) : - # dans cette mthode, on change le comportement - # de la mthode calcul tout en se servant de celui - # de la classe mre - return ma_classe.calcul (self) * self.att1 - -a = ma_classe (2) -b = ma_classe2 (2) -print (a.att2) # affiche 4 = 2 * 2 -print (b.att2) # affiche 8 = (2*2) * 2 -\end{verbatimx} - - -\subsection{Dcorateur}\indexfr{dcorateur} - -Le langage \pythons permet quelques simplifications de code avec les dcorateurs comme dans l'exemple suivant~: - -\begin{verbatimx} -def makebold(fn): - def wrapped(): - return "" + fn() + "" - return wrapped - -def makeitalic(fn): - def wrapped(): - return "" + fn() + "" - return wrapped - -@makebold -@makeitalic -def hello(): - return "hello world" - -print (hello()) ## returns hello world -\end{verbatimx} - -Il est possible aussi de dfinir des proprits ou \textit{properties}. Cela permet de sparer l'affectation de l'accs un membre d'une classe sans changer la notation~:\indexfr{proprit}\indexfr{property} - -\begin{verbatimx} -class C(object): - def __init__ (self) : - self._p = 1 - @property - def p(self): - return self._p - @p.setter - def p(self, val): - self._p = val * 2 - -obj = C() -print (obj.p) # utilise p_get, affiche 1 -obj.p = 5 # utilise p_set -print (obj.p) # utilise p_get affiche 10 -\end{verbatimx} - - -\section{Fichiers}\indexfr{fichier} - -L'criture et la lecture dans un fichier s'effectuent toujours de la mme manire. On ouvre le fichier en mode criture ou lecture, on crit ou on lit, puis on ferme le fichier, le laissant disponible pour une utilisation ultrieure. Ce paragraphe ne prsente pas l'criture ou la lecture dans un format binaire car celle-ci est peu utilise dans ce langage. - - -\subsection{Ecriture dans un fichier texte} - -L'criture dans un fichier texte s'effectue toujours selon le mme schma~: -% -\begin{verbatimx} -f = open ("nom-fichier", "w") # ouverture en mode criture "w" ou criture ajout "a" - -f.write ( s ) # criture de la chane de caractres s -f.write ( s2 ) # criture de la chane de caractres s2 -... - -f.close () # fermeture -\end{verbatimx} -% -Certains codes sont fort utiles lors de l'criture de fichiers texte~: -\begin{center} -\begin{tabular}{ll} -\codes{\backslash n} & passage la ligne \\ -\codes{\backslash t} & insertion d'une tabulation, indique un passage la colonne suivante dans le logiciel Excel -\end{tabular} -\end{center} - -\textbf{Version 3.x :} une autre criture est possible qui permet d'viter l'appel la mthode \codes{close}.\label{section_res_fichier} -\begin{verbatimx} -with open ("nom-fichier", "w") as f : - f.write ( s ) - f.write ( s2 ) -\end{verbatimx} - -L'usage d'un encoding est frquent lorsqu'on manipule des fichiers issus d'Internet. Le plus rpandu est \codes{utf8}. Il est spcifi en-tte des pages web tlcharges. L'exemple qui suit n'est valable qu'avec la version~3. Il est recommand de l'utiliser ds qu'on manipule les encodings. -\begin{verbatimx} -with open ("nom-fichier", "w", encoding = "utf8") as f : - f.write ( s ) - f.write ( s2 ) -\end{verbatimx} - -\subsection{Lecture dans un fichier texte} - -La lecture est le symtrique de l'criture. En voici un exemple, la seule chose qui change d'un programme l'autre est ce qu'on fait des lignes extraites. -% -\begin{verbatimx} -f = open ("essai.txt", "r") # ouverture du fichier en mode lecture -l = f.readlines () # lecture de toutes les lignes, - # elles sont places dans une liste -f.close () # fermeture du fichier - -for s in l : print (s) # on affiche les lignes l'cran -\end{verbatimx} - -\textbf{Version 3.x :} la mme syntaxe avec le mot-cl \codes{with} et l'encoding existe. - -\begin{xremark}{code de fin de ligne} -Lors le programme prcdent lit une ligne dans un fichier, le rsultat lu inclut le ou les caractres (\codes{\backslash n \; \backslash r} qui marquent la fin d'une ligne. C'est pour cela que la lecture est parfois suivie d'une tape de nettoyage. \indexfrr{fichier}{fin de ligne} -% -\begin{verbatimx} -f = open ("essai.txt", "r") # ouverture du fichier en mode lecture -l = f.readlines () # lecture de toutes les lignes, - # elles sont places dans une liste places dans une liste -f.close () # fermeture du fichier - -l_net = [] # contiendra la liste nettoye des lignes du fichier -for s in l : - s2 = s.replace ("\n", "") # on supprime le code de fin de ligne \n - s2 = s2.replace ("\r", "") # on supprime le code de fin de ligne \r - # (Windows uniquement) - s2 = s2.strip("\r\n") # cette ligne est quivalente aux deux prcdentes - l_net.append (s2) # on ajoute le rsultat la liste nettoye -\end{verbatimx} -\end{xremark} - -\begin{xremark}{fichier format} -Les fichiers textes ont de nombreux formats, on peut citer HTML ou XML qui sont des formats balises. Leur lecture utilise des modules comme \codes{HTMLParser} ou \codes{xml.sax} dont la description sort du cadre de ce document.\indexfrr{HTML}{lecture}\indexfrr{XML}{lecture}\indexfrr{fichier}{HTML}\indexfrr{fichier}{XML} Un autre format est souvent utilis avec le logiciel \textit{Excel}\indexoutil{Excel} ou tout autre tableur. Lorsqu'on enregistre une feuille de calcul sous format texte, le fichier obtenu est organis en colonnes~: sur une mme ligne, les informations sont disposes en colonnes dlimites par un sparateur qui est souvent une tabulation (\codes{\backslash t}) ou un point virgule. -% -\begin{verbatimx} -nom ; prnom ; livre -Hugo ; Victor ; Les misrables -Kessel ; Joseph ; Le lion -Woolf ; Virginia ; Mrs Dalloway -Calvino ; Italo ; Le baron perch -\end{verbatimx} -% -Pour lire ce fichier, il est ncessaire de scinder chaque ligne en une liste de chanes de caractres. On utilise pour cela la mthode \codes{split} des chanes de caractres. -% -\begin{verbatimx} -f = open ("essai.txt", "r") # ouverture du fichier en mode lecture -l = f.readlines () # lecture de toutes les lignes, places dans une liste -f.close () # fermeture du fichier - -for s in l : - s2 = s.replace ("\n", "") # on supprime le code de fin de ligne \n - s2 = s2.replace ("\r", "") # on supprime le code de fin de ligne \r (Windows uniquement) - case = s2.split (";") - if len (case) >= 3 : - print (case [1], " ", case [0], " a crit ", case [2]) - # Version 2.x : print ... -\end{verbatimx} -\end{xremark} - - -\section{Modules}\indexfr{module} - -Le concept de module permet de rpartir diffrentes parties d'un programme sur plusieurs fichiers. Il existe deux types de modules~: ceux disponibles sur Internet (programms par d'autres) et ceux que l'on programme soi-mme. Les premiers sont souvent fournis avec un programme d'installation automatique ou dans le cas o ils sont manquants, des instructions permettant de l'installer. Les seconds sont crits dans le mme rpertoire que le fichier principal. On enregistre le module suivant sous le nom \codes{geometrie.py}. -% -\begin{verbatimx} -# dfinition du module geometrie.py - -def carre (x) : - return x ** 2 - -class point : - def __init__ (self,x,y) : - self.x, self.y = x,y - - def norme (self) : - return (self.x ** 2 + self.y ** 2) ** 0.5 -\end{verbatimx} -% -Pour utiliser une fonction ou une classe du module \codes{geometrie.py}, on utilise une des syntaxes suivantes~: -% -\begin{enumerate} -\item Premire syntaxe~: -\begin{verbatimx} -import geometrie -print (geometrie.carre (1.5)) -p = geometrie.point (1,2) -\end{verbatimx} -% -\item Deuxime syntaxe~: -\begin{verbatimx} -import geometrie as GEO # on donne un pseudonyme au module geometrie -print (GEO.carre (1.5)) -p = GEO.point (1,2) -\end{verbatimx} -% -\item Troisime syntaxe~: le module est utilis trs souvent, mme un pseudonyme est trop long, il faut nanmoins s'assurer que les modules imports de cette mme manire n'incluent pas des fonctions ou classes portant des noms identiques. Dans ce cas, c'est toujours le dernier qui gagne. -\begin{verbatimx} -from geometrie import * -print (carre (1.5)) -p = point (1,2) -\end{verbatimx} -% -\end{enumerate} -% -Dans le cas des modules installs, les trois syntaxes d'utilisation sont aussi valables. On voit aussi souvent apparatre dans un module la condition~: -% -\begin{verbatimx} -if __name__ == "__main__" : - # quelques instructions ici -\end{verbatimx} -% -Ces instructions ne sont excutes que si le module est utilis en tant que programme principal. Lorsque ce fichier est import, elles ne sont jamais excutes. Cela permet d'crire des instructions qui permettent de vrifier si le module ne contient pas d'erreurs. Une fois cette tape effectue, il ne sert rien de la rpter chaque fois que le module est import. C'est pourquoi elles ne sont excutes que si la condition \codes{if \;\_\_name\_\_ == "\_\_main\_\_" :} est vrifie, c'est--dire si le module est le programme principal et non un module. - - - - - -\section{Exceptions}\indexfr{exception} - - -Le petit programme suivant dclenche une erreur parce qu'il effectue une division par zro. -% -\begin{verbatimx} -def inverse (x): - y = 1.0 / x - return y -b = inverse (0) -print (b) -\end{verbatimx} -% -Il dclenche une erreur ou ce qu'on appelle une \emph{exception}. -% -\begin{verbatimx} -Traceback (most recent call last): - File "cours.py", line 2, in ? - y = 1.0 / x -ZeroDivisionError: float division -\end{verbatimx} -% -Le mcanisme des exceptions permet au programme de "rattraper" les erreurs, de dtecter qu'une erreur s'est produite et d'agir en consquence afin que le programme ne s'arrte pas~: -% -\begin{verbatimx} -def inverse (x): - y = 1.0 / x - return y -try : - b = inverse (0) # dclenche une exception - print (b) -except : - print ("le programme a dclench une erreur") -\end{verbatimx} -% -On protge la partie du code l'aide des mots-cls \codes{try} et \codes{except}. Entre ces deux instructions, s'il se produit une erreur, le programme passe immdiatement ce qui suit l'instruction \codes{except}. On peut mme rcuprer le message d'erreur correspondant~: -% -\begin{verbatimx} -def inverse (x): - y = 1.0 / x - return y -try : - print (inverse (2)) - print (inverse (0)) -except Exception as exc: - print ("exception de type ", exc.__class__) - # affiche exception de type exceptions.ZeroDivisionError - print ("message ", exc) - # affiche le message associ l'exception -\end{verbatimx} -% -On peut aussi dcider que le programme agira diffremment selon l'erreur produite. Dans l'exemple suivant, le programme teste d'abord si l'erreur est de type \codes{ZeroDivisionError} auquel cas il affiche le message \textit{division par zro}. Pour un autre type d'erreur, il regarde s'il y a d'autres instructions \codes{except} qui s'y rapportent. S'il y en a une, il excute les lignes qui la suivent, sinon, le programme s'arrte et dclenche une erreur. -% -\begin{verbatimx} -def inverse (x): - y = 1.0 / x - return y -try : - print ((-2.1) ** 3.1) - print (inverse (2)) - print (inverse (0)) -except ZeroDivisionError: - print ("division par zro") -except Exception as exc: - print ("erreur insouponne : ", exc.__class__) - print ("message ", exc) -\end{verbatimx} -% -Les instructions \codes{try} et \codes{except} peuvent apparatre dans le programme principal, dans une boucle, un test, une fonction, s'imbriquer les unes dans les autres. Il est possible de dclencher soi-mme une exception avec l'instruction \codes{raise} et ou de dfinir ses propres exceptions en crant une classe hritant d'une classe d'exception. L'exemple suivant regroupe tous ces cas. -% -\begin{verbatimx} -class AucunChiffre (Exception) : - """chane de caractres contenant - aussi autre chose que des chiffres""" - - def __init__(self, s, f = "") : - Exception.__init__(self, s) - self.s = s - self.f = f - - def __str__(self) : - return """exception AucunChiffre, lance depuis la fonction """ + self.f + \ - " avec le paramtre " + self.s - -def conversion (s) : - """conversion d'une chane de caractres en entier""" - if not s.isdigit () : - raise AucunChiffre, (s, "conversion") - return int (s) - -try : - s = "123a" - i = conversion (s) - print (s, " = ", i) -except AucunChiffre as exc : - print (AucunChiffre.__doc__, " : ", exc) - print ("fonction : ", exc.f) -\end{verbatimx} - - -\section{Erreurs, confusions frquentes} - -\subsection{Variables} - -\subsubsection{Chane de caractres = tableau de caractres} -\indexfrr{confusion}{chane = tableau} - -Une chane de caractres est un tableau de caractres~: pour accder un caractre, on procde comme pour une liste. -% -\begin{verbatimx} -s = "abcdefghijklmnopqrstuvwxyz" -print (s [4]) # affiche "e" -print (s [4:6]) # affiche "ef" -\end{verbatimx} - - - -\subsubsection{Guillemets ou pas} -\indexfr{guillemet} -Doit-on mettre des guillemets ou non~? -% -\begin{verbatimx} -l = [ un, deux, trois, quatre ] -up = [] -for i in range (0, len (l)) : - up.append ( l [i].upper () ) -\end{verbatimx} -% -Le code prcdent ne fonctionne pas car il n'y a pas de guillemets autour de \codes{un}, \codes{deux}, \codes{trois}, \codes{quatre}. Le langage considre alors ces quatre mots comme des variables~: un identificateur qui dsigne une information. Mais comme ces variables n'existent pas, ces identifiants ne sont relis aucun contenu et l'interprteur \pythons ne comprend pas. - -Un mot entour de guillemets (ou d'apostrophes) dfinit un contenu. Sans guillemet (ou apostrophe), il dfinit une variable qui permet de manipuler un contenu tout simplement en donnant la possibilit au programmeur de le nommer. Autrement dit, pour manipuler une chane de caractres, il faut affecter ce contenu une variable. Les guillemets n'apparaissent plus par la suite car on doit utiliser la variable pour la manipuler. - - -\subsection{Boucles} - -\subsubsection{\codes{range} ou pas \codes{range} } -\indexfrr{boucle}{for}\indexfrr{boucle}{while} -% -Les deux programmes suivant sont quivalents. La seule diffrence rside dans l'criture dans la boucle \codes{for} qui utilise dans le premier cas la fonction \codes{range} et dans l'autre non. -% -\begin{verbatimx} -l = [ "un", "deux", "trois", "quatre" ] -up = [] -for i in range (0, len (l)) : - up.append ( l [i].upper () ) -\end{verbatimx} -% -Lorsqu'on utilise la fonction \codes{range}, on dispose lors de la boucle de deux informations, l'indice \codes{i} et l'lment \codes{l [i]}. Si l'indice n'est pas utile, il est possible de simplifier la boucle comme suit. -% -\begin{verbatimx} -l = [ "un", "deux", "trois", "quatre" ] -up = [] -for m in l : - up.append ( m.upper () ) -\end{verbatimx} -% -En gnral, on se sert de la boucle qui utilise la fonction \codes{range} dans deux cas~: -\begin{enumerate} -\item On souhaite faire des oprations sur les lments qui prcdent ou suivent l'lment en question, ce qui ncessite de connatre l'indice. -\item On parcourt deux listes de mme taille la fois~: l'indice dsigne la position de deux lments, un dans chaque liste. -\end{enumerate} - -\subsubsection{Initialisation} -\indexfrr{confusion}{initialisation d'une boucle} - -Une boucle est souvent utilise pour faire une somme, calculer un maximum~: garder un unique rsultat en parcourant une liste. Une boucle de ce type est toujours prcde d'une tape d'initialisation qui consiste donner une valeur au rsultat~: celle qu'il aurait si la liste tait vide. -% -\begin{verbatimx} -l = [ "un", "deux", "trois", "quatre" ] -s = "" -for m in l : - s += m # concatnation des mots en une seule chane de caractres -\end{verbatimx} - - -\subsection{Fonctions} - -\subsubsection{Diffrence entre \codes{print} et \codes{return}} -\indexfrr{confusion}{diffrence entre \codes{print} et \codes{return}} - -A la fin d'un calcul, afin de voir son rsultat, on utilise souvent l'instruction \codes{print}. On peut se demander alors si la fin de chaque fonction, il ne faudrait pas utiliser l'instruction \codes{print}. A quoi servirait alors l'instruction \codes{return}~? On suppose qu'un calcul est en fait le rsultat de trois calculs la suite~: -\begin{verbatimx} -a = calcul1 (3) -b = calcul2 (a) -c = calcul3 (b) # c rsultat souhait et affich -\end{verbatimx} -% -Chaque terme \codes{calculx} cache une fonction or seul le rsultat de la dernire nous intresse et doit tre affich. Pour les deux premires, la seule chose importante est que leur rsultat soit transmis la fonction suivante et ceci ne peut se faire que grce l'instruction \codes{return}. L'instruction \codes{print} insre dans le code de la fonction \codes{calcul1} ou \codes{calcul2} permettra d'afficher le rsultat mais ne le transmettra pas~: l'instruction \codes{return} est donc indispensable, \codes{print} facultative. - -En revanche, dans la dernire fonction \codes{calcul3}, il est possible de se passer de \codes{return} et de se contenter uniquement d'un \codes{print}. Cependant, il est conseill d'utiliser quand mme \codes{return} au cas o le rsultat de la fonction \codes{calcul3} serait utilis par une autre fonction, \codes{calcul4} par exemple. - -\begin{verbatimx} -def calcul1(x) : - return x+3 -y = calcul1(4) -print (y) # affiche None - # car la fonction calcul1 ne retourne pas de rsultat, elle l'affiche -\end{verbatimx} - -Cela peut provoquer des erreurs lorsqu'on essaye d'utiliser ce rsultat dans un calcul par la suite. - -\begin{verbatimx} -def calcul1(x) : print (x+3) -def calcul2(x) : return calcul1(x) + 5 -y = calcul2(4) # affiche l'erreur - # ported operand type(s) for +: 'NoneType' and 'int' -\end{verbatimx} - - - - - -\section{Trois conseils pour crire un programme} - -\subsection{Des petites fonctions} - -Pour plusieurs raisons~: -\begin{enumerate} -\item Il est plus facile de corriger un programme qui est constitu de petites fonctions plutt que de quelques grandes. Chaque fonction peut tre vrifie sparment. -\item Il est plus facile de rutiliser des petites fonctions. -\item Il est plus facile de rpartir le travail sur plusieurs personnes. -\end{enumerate} - -\begin{xremark}{variables globales} -Il vaut mieux viter les variables globales qui sont considres que comme des paramtres cachs. -\end{xremark} - - - -\subsection{Sparer les calculs, le chargement des donnes, l'interface graphique} - -Pour plusieurs raisons~: -\begin{enumerate} -\item Il est plus facile de vrifier un calcul s'il est dans une fonction indpendante plutt que cach dans le code d'une interface graphique. -\item C'est facile de faire un calcul une fois lorsqu'un utilisateur appuie sur un bouton, si on veut faire ce calcul cent fois, on ne peut pas lui demander d'appuyer cent fois sur le mme bouton. -\item Les calculs ou le chargement des donnes peuvent tre utiliss dans d'autres programmes. -\end{enumerate} - -\subsection{Utiliser des fonctions de tests} - -Ces fonctions peuvent tre excutes au dbut du programme pour vrifier que certaines parties du programme fonctionnent toujours mme aprs les avoir modifies. - -L'exemple suivant considre une fonction qui doit retourner une somme relle mme si les lments de la liste sont entiers. On crit la fonction qui vrifie cela. - -\begin{verbatimx} -def somme_double (liste) : - return 1.0 * sum(liste) - -def test_somme_double () : - y = somme_double([ 1 ]) / 2 - if y == 0 : raise Exception ("valeur > 0 attendue") - -if __name__ == "__main__" : - test_somme_double() -\end{verbatimx} - -Si plus tard, quelqu'un modifie la fonction \codes{somme\_double} en enlevant la multiplication parce qu'il considre cela inutile. La fonction de test provoquera une erreur. Elle est l pour rappeler que la fonction a t programme pour retourner un nombre rel et que quiconque l'utilise s'attend ce qu'elle retourne ce type de rsultat. - -\begin{verbatimx} -Traceback (most recent call last): - File "conseil.py", line 10, in - test_somme_double() - File "conseil.py", line 7, in test_somme_double - if y == 0 : raise Exception ("valeur > 0 attendue") -Exception: valeur > 0 attendue -\end{verbatimx} - -\section{Trucs et astuces} - - -\subsection{Partager du code} - -Il existe aujourd'hui des solutions qui permettent d'viter les envois de programme par email. Des outil comme \textit{DropBox}, \textit{SkyDrive}, \textit{GoogleDrive} permettent de partager un rpertoire. Un mme rpertoire peut tre partag sur plusieurs ordinateurs et plusieurs personnes. Une modification (y compris une suppression) sur l'une des rpliques sera propage sur tous les ordinateurs ds qu'ils sont connects Internet. - -Il est possible de coupler cette solution avec \textit{SVN} ou \textit{TortoiseSVN} qui sont des logiciels de suivis de source. On garde la fois la dernire version et l'historique des modifications\footnote{\httpstyle{http://mlevit.wordpress.com/2009/11/18/how-to-use-subversion-dropbox-to-create-an-effective-work-managementbackup-system/}}. - - -\subsection{Moteurs de recherche} - -Lorsqu'on ne comprend un message d'erreur, il est souvent utile de recopier le texte dans un moteur de recherche (Google, Bing, ...). Il est trs rare de ne pas russir trouver d'indices. - - - - - - -\section{Rfrences} - -\subsection{Quelques sites} - -\begin{itemize} -\item \httpstyle{http://www.siteduzero.com/informatique/tutoriels/apprenez-a-programmer-en-python} -\item \httpstyle{https://www.khanacademy.org/science/computer-science/v/introduction-to-programs-data-types-and-variables} -\end{itemize} - - -\subsection{Quelques modules} - -\begin{itemize} -\item \codes{numpy}~: calcul matriciel. -\item \codes{scipy}~: calcul scientifique. -\item \codes{matplotlib}~: graphique. -\item \codes{pygame}~: jeux. -\item \codes{PyQt}~: interface graphique. -\item \codes{NetworkX}~: dessiner des graphes. -\end{itemize} - - -\subsection{Quelques livres} - -\begin{itemize} -\item \citeindex{Pilgrim2011}~: livre trs dtaill sur le langage et ses modules. -\item \citeindex{Swinnen2012}~: initiation au langage. -\item \citeindex{Dupr2011}~: initiation au langage et exercices. -\item \citeindex{Ziad2011}~: aborde le langage et diffrent aspects de l'utilisation du langage pour construire une application robuste (tests unitaires...) -\item \citeindex{Dayley2007}~: rsum du langage, peu d'explications, beaucoup d'exemples, aborde beaucoup de sujets (envoyer un email, internet, ...). - Bonne source pour u copier/coller. -\item \citeindex{Brucher2008}, \citeindex{Bailly2008}~: pour les experts qui souhaitent crire des programmes en \pythons et \textit{C++}. -\item \citeindex{McKinney2012}~: pour faire de l'analyse des donnes avec \python. -\end{itemize} - - -\firstpassagedo{ - \subsection{Bibliographie} - \begin{thebibliography}{99} - \input{python_cours_biblio.tex} - \end{thebibliography} - %\section{Index} - \begin{flushleft} - \printindex - \end{flushleft} -} - - - -\input{../../common/paper_end.tex}% - diff --git a/_unittests/ut_documentation/test_run_notebooks_numpy.py b/_unittests/ut_documentation/test_run_notebooks_numpy.py deleted file mode 100644 index d4781ce9..00000000 --- a/_unittests/ut_documentation/test_run_notebooks_numpy.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -""" -@brief test log(time=33s) -""" -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import get_temp_folder -from pyquickhelper.ipythonhelper import execute_notebook_list, execute_notebook_list_finalize_ut -import teachpyx - - -class TestRunNotebooksNumpy(unittest.TestCase): - - def test_run_notebook_pandas(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - temp = get_temp_folder(__file__, "temp_run_notebooks_numpy") - - # selection of notebooks - fnb = os.path.normpath(os.path.join( - os.path.abspath(os.path.dirname(__file__)), "..", "..", "_doc", "notebooks", "numpy")) - keepnote = [] - for f in os.listdir(fnb): - if os.path.splitext(f)[-1] == ".ipynb" and "_long" not in f: - keepnote.append(os.path.join(fnb, f)) - - # run the notebooks - res = execute_notebook_list(temp, keepnote, fLOG=fLOG) - execute_notebook_list_finalize_ut(res, fLOG=fLOG, dump=teachpyx) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_documentation/test_run_notebooks_pandas.py b/_unittests/ut_documentation/test_run_notebooks_pandas.py deleted file mode 100644 index 73c6fa21..00000000 --- a/_unittests/ut_documentation/test_run_notebooks_pandas.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -""" -@brief test log(time=33s) -""" -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import get_temp_folder -from pyquickhelper.ipythonhelper import execute_notebook_list, execute_notebook_list_finalize_ut -import teachpyx - - -class TestRunNotebooksPandas(unittest.TestCase): - - def test_run_notebook_pandas(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - temp = get_temp_folder(__file__, "temp_run_notebooks_pandas") - - # selection of notebooks - fnb = os.path.normpath(os.path.join( - os.path.abspath(os.path.dirname(__file__)), "..", "..", "_doc", "notebooks", "pandas")) - keepnote = [] - for f in os.listdir(fnb): - if os.path.splitext(f)[-1] == ".ipynb" and "_long" not in f: - keepnote.append(os.path.join(fnb, f)) - - # run the notebooks - res = execute_notebook_list(temp, keepnote, fLOG=fLOG) - execute_notebook_list_finalize_ut(res, fLOG=fLOG, dump=teachpyx) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_documentation/test_run_notebooks_python.py b/_unittests/ut_documentation/test_run_notebooks_python.py deleted file mode 100644 index fc0524c1..00000000 --- a/_unittests/ut_documentation/test_run_notebooks_python.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -""" -@brief test log(time=33s) -""" -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import get_temp_folder -from pyquickhelper.ipythonhelper import execute_notebook_list, execute_notebook_list_finalize_ut -import teachpyx - - -class TestRunNotebooksPython(unittest.TestCase): - - def test_run_notebook_python(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - temp = get_temp_folder(__file__, "temp_run_notebooks_python") - - # selection of notebooks - fnb = os.path.normpath(os.path.join( - os.path.abspath(os.path.dirname(__file__)), "..", "..", "_doc", "notebooks", "python")) - keepnote = [] - for f in os.listdir(fnb): - if os.path.splitext(f)[-1] == ".ipynb" and "_long" not in f and "protobuf" not in f: - keepnote.append(os.path.join(fnb, f)) - - # run the notebooks - res = execute_notebook_list(temp, keepnote, fLOG=fLOG) - execute_notebook_list_finalize_ut(res, fLOG=fLOG, dump=teachpyx) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_documentation/test_run_notebooks_python_protobuf.py b/_unittests/ut_documentation/test_run_notebooks_python_protobuf.py deleted file mode 100644 index 86b89b43..00000000 --- a/_unittests/ut_documentation/test_run_notebooks_python_protobuf.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- -""" -@brief test log(time=67s) -""" -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import get_temp_folder, skipif_travis -from pyquickhelper.ipythonhelper import execute_notebook_list, execute_notebook_list_finalize_ut -import teachpyx - - -class TestRunNotebooksPythonProtobuf(unittest.TestCase): - - @skipif_travis("'Permission denied: 'bin/protoc'") - def test_run_notebook_python_protobuf(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - temp = get_temp_folder(__file__, "temp_run_notebooks_python_protobuf") - - # selection of notebooks - fnb = os.path.normpath(os.path.join( - os.path.abspath(os.path.dirname(__file__)), "..", "..", "_doc", "notebooks", "python")) - keepnote = [] - for f in os.listdir(fnb): - if os.path.splitext(f)[-1] == ".ipynb" and "protobuf" in f: - keepnote.append(os.path.join(fnb, f)) - - # run the notebooks - res = execute_notebook_list(temp, keepnote, fLOG=fLOG) - execute_notebook_list_finalize_ut(res, fLOG=fLOG, dump=teachpyx) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_examples/test_classique.py b/_unittests/ut_examples/test_classique.py index 9adbdec6..7a999922 100644 --- a/_unittests/ut_examples/test_classique.py +++ b/_unittests/ut_examples/test_classique.py @@ -1,17 +1,15 @@ -""" -@brief test log(time=1s) - -You should indicate a time in seconds. The program ``run_unittests.py`` -will sort all test files by increasing time and run them. -""" import unittest from datetime import datetime -from teachpyx.examples.classiques import commentaire_accentues, dix_entiers_carre, repetition_a_eviter, dictionnaire_modifie_dans_la_boucle +from teachpyx.examples.classiques import ( + commentaire_accentues, + dix_entiers_carre, + repetition_a_eviter, + dictionnaire_modifie_dans_la_boucle, +) from teachpyx.examples.classiques import str2date class TestClassiques(unittest.TestCase): - def test_fonctions(self): commentaire_accentues() r = dix_entiers_carre() @@ -21,8 +19,7 @@ def test_fonctions(self): r2 = repetition_a_eviter([4, 5], True) self.assertEqual(r2, 0.25) r = dictionnaire_modifie_dans_la_boucle() - self.assertEqual( - r, ([0, 1, 2, 4, 5, 6], {0: 0, 1: 1, 2: 2, 5: 5, 6: 6})) + self.assertEqual(r, ([0, 1, 2, 4, 5, 6], {0: 0, 1: 1, 2: 2, 5: 5, 6: 6})) r = str2date("11/8/1975") self.assertEqual(r, datetime(1975, 8, 11)) diff --git a/_unittests/ut_examples/test_classique_permutation.py b/_unittests/ut_examples/test_classique_permutation.py index 1a357f82..d83de773 100644 --- a/_unittests/ut_examples/test_classique_permutation.py +++ b/_unittests/ut_examples/test_classique_permutation.py @@ -1,16 +1,12 @@ -""" -@brief test log(time=1s) - -You should indicate a time in seconds. The program ``run_unittests.py`` -will sort all test files by increasing time and run them. -""" import unittest import itertools -from teachpyx.examples.construction_classique import enumerate_permutations_recursive, enumerate_permutations - +from teachpyx.examples.construction_classique import ( + enumerate_permutations_recursive, + enumerate_permutations, +) -class TestClassiquesPermutation (unittest.TestCase): +class TestClassiquesPermutation(unittest.TestCase): def test_permutation(self): self.maxDiff = None ens = list(range(5)) diff --git a/_unittests/ut_examples/test_construction_classique.py b/_unittests/ut_examples/test_construction_classique.py index cde8574c..f259c976 100644 --- a/_unittests/ut_examples/test_construction_classique.py +++ b/_unittests/ut_examples/test_construction_classique.py @@ -1,19 +1,21 @@ -""" -@brief test log(time=1s) - -You should indicate a time in seconds. The program ``run_unittests.py`` -will sort all test files by increasing time and run them. -""" import unittest from teachpyx.examples.construction_classique import ( - recherche, minindex, text2mat, compte, - integrale, vect2mat, mat2vect, recherche_dichotomique, - mat2text, triindex, construit_matrice_carree, - somme) + recherche, + minindex, + text2mat, + compte, + integrale, + vect2mat, + mat2vect, + recherche_dichotomique, + mat2text, + triindex, + construit_matrice_carree, + somme, +) class TestConstructionClassique(unittest.TestCase): - def test_fonction(self): self.assertEqual(recherche([2, 3, 45], 3), 1) self.assertEqual(recherche([2, 3, 45], 4), -1) @@ -27,10 +29,10 @@ def test_fonction(self): self.assertEqual(t, s) tab = ["zero", "un", "deux"] r = triindex(tab) - self.assertEqual(r, [('deux', 2), ('un', 1), ('zero', 0)]) + self.assertEqual(r, [("deux", 2), ("un", 1), ("zero", 0)]) li = ["un", "deux", "un", "trois"] r = compte(li) - self.assertEqual(r, {'trois': 1, 'deux': 1, 'un': 2}) + self.assertEqual(r, {"trois": 1, "deux": 1, "un": 2}) mat = [[0, 1, 2], [3, 4, 5]] r = mat2vect(mat) self.assertEqual(r, [0, 1, 2, 3, 4, 5]) diff --git a/_unittests/ut_examples/test_numpysex.py b/_unittests/ut_examples/test_numpysex.py index c5f9edb9..90345dc0 100644 --- a/_unittests/ut_examples/test_numpysex.py +++ b/_unittests/ut_examples/test_numpysex.py @@ -1,16 +1,9 @@ -""" -@brief test log(time=1s) - -You should indicate a time in seconds. The program ``run_unittests.py`` -will sort all test files by increasing time and run them. -""" import unittest import numpy from teachpyx.examples.numpysex import numpy_matrix2list, numpy_types class TestNumpys(unittest.TestCase): - def test_numpys(self): exp = [[0, 1, 2], [4, 5, 6]] mat = numpy.array(exp) diff --git a/_unittests/ut_faq/test_faq_exception.py b/_unittests/ut_faq/test_faq_exception.py index 45e56562..3c1f2bcb 100644 --- a/_unittests/ut_faq/test_faq_exception.py +++ b/_unittests/ut_faq/test_faq_exception.py @@ -1,13 +1,9 @@ -""" -@brief test log(time=2s) -""" import unittest -from pyquickhelper.pycode import ExtTestCase +from teachpyx.ext_test_case import ExtTestCase from teachpyx.faq.faq_exception import call_stack class TestFaqException(ExtTestCase): - def test_call_back(self): def insidef(): ft = call_stack() diff --git a/_unittests/ut_faq/test_faq_missing.py b/_unittests/ut_faq/test_faq_missing.py index 775bbefc..6ff7e586 100644 --- a/_unittests/ut_faq/test_faq_missing.py +++ b/_unittests/ut_faq/test_faq_missing.py @@ -1,17 +1,28 @@ -""" -@brief test log(time=4s) -""" import unittest import warnings from datetime import datetime -from pyquickhelper.pycode import ExtTestCase -from teachpyx.faq.faq_python import entier_grande_taille, difference_div, python_path, same_variable, stringio -from teachpyx.faq.faq_python import property_example, enumerate_regex_search, sortable_class, list_of_installed_packages -from teachpyx.faq.faq_python import information_about_package, get_month_name, get_day_name +from teachpyx.ext_test_case import ExtTestCase +from teachpyx.faq.faq_python import ( + entier_grande_taille, + difference_div, + python_path, + same_variable, + stringio, +) +from teachpyx.faq.faq_python import ( + property_example, + enumerate_regex_search, + sortable_class, + list_of_installed_packages, +) +from teachpyx.faq.faq_python import ( + information_about_package, + get_month_name, + get_day_name, +) class TestFaqMissing(ExtTestCase): - def test_faq_pythonm(self): entier_grande_taille() difference_div() @@ -22,8 +33,8 @@ def test_faq_pythonm(self): property_example() self.assertNotEmpty(list(enumerate_regex_search("r*", "rararr"))) sortable_class([5, 5]) - self.assertEqual(get_month_name(datetime(2016, 4, 5)), 'April') - self.assertEqual(get_day_name(datetime(2016, 4, 17)), 'Sunday') + self.assertEqual(get_month_name(datetime(2016, 4, 5)), "April") + self.assertEqual(get_day_name(datetime(2016, 4, 17)), "Sunday") def test_faq_pythonm_pip(self): try: diff --git a/_unittests/ut_faq/test_faq_numpy.py b/_unittests/ut_faq/test_faq_numpy.py index fc4a5bb8..2e3b0800 100644 --- a/_unittests/ut_faq/test_faq_numpy.py +++ b/_unittests/ut_faq/test_faq_numpy.py @@ -1,13 +1,9 @@ -""" -@brief test log(time=7s) -""" import unittest import math from teachpyx.faq.faq_numpy import to_float32 class TestFaqNumpy(unittest.TestCase): - def test_missing(self): pi = math.pi fpi = to_float32(pi) diff --git a/_unittests/ut_faq/test_faq_python.py b/_unittests/ut_faq/test_faq_python.py index e41f01ff..e2e0f364 100644 --- a/_unittests/ut_faq/test_faq_python.py +++ b/_unittests/ut_faq/test_faq_python.py @@ -1,14 +1,9 @@ -""" -@brief test log(time=7s) -""" import unittest import datetime -from teachpyx.faq.faq_python import ( - get_month_name, get_day_name, class_getitem) +from teachpyx.faq.faq_python import get_month_name, get_day_name, class_getitem class TestFaqPython(unittest.TestCase): - def test_month_name(self): dt = datetime.datetime(2016, 1, 25) name = get_month_name(dt) diff --git a/_unittests/ut_module/test___init__.py b/_unittests/ut_module/test___init__.py deleted file mode 100644 index d4c2272f..00000000 --- a/_unittests/ut_module/test___init__.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -@brief test log(time=0s) -""" -import unittest -from teachpyx import check, _setup_hook - - -class TestInit(unittest.TestCase): - - def test_check(self): - assert check() - _setup_hook() - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_module/test_code_style.py b/_unittests/ut_module/test_code_style.py deleted file mode 100644 index 5af1b29d..00000000 --- a/_unittests/ut_module/test_code_style.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -@brief test log(time=0s) -""" - -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import check_pep8 - - -class TestCodeStyle(unittest.TestCase): - - def test_code_style_src(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - thi = os.path.abspath(os.path.dirname(__file__)) - src_ = os.path.normpath(os.path.join(thi, "..", "..", "src")) - check_pep8(src_, fLOG=fLOG, - pylint_ignore=('C0103', 'C1801', 'R1705', 'W0108', 'W0613', - 'W0212', 'W0107', 'C0415', 'C0209'), - skip=['construction_classique.py:577: C0200', - "Redefining built-in 'format'", - "data_bikes.py:1: F0002"]) - - def test_code_style_test(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - thi = os.path.abspath(os.path.dirname(__file__)) - test = os.path.normpath(os.path.join(thi, "..", )) - check_pep8(test, fLOG=fLOG, neg_pattern="temp_.*", - pylint_ignore=('C0111', 'C0103', 'W0622', 'C1801', 'C0412', - 'W0122', 'W0123', 'E1101', 'R1705', - 'W0703', 'W0107', 'C0415', 'C0209'), - skip=["Unused argument 'cell'", - ]) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_module/test_convert_notebooks.py b/_unittests/ut_module/test_convert_notebooks.py deleted file mode 100644 index 09fe244f..00000000 --- a/_unittests/ut_module/test_convert_notebooks.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -@brief test log(time=0s) -""" -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.filehelper import explore_folder_iterfile -from pyquickhelper.ipythonhelper import upgrade_notebook, remove_execution_number - - -class TestConvertNotebooks(unittest.TestCase): - - def test_convert_notebooks(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - fold = os.path.abspath(os.path.dirname(__file__)) - fold2 = os.path.normpath( - os.path.join(fold, "..", "..", "_doc", "notebooks")) - for nbf in explore_folder_iterfile(fold2, pattern=".*[.]ipynb"): - t = upgrade_notebook(nbf) - if t: - fLOG("modified", nbf) - # remove numbers - remove_execution_number(nbf, nbf) - - fold2 = os.path.normpath(os.path.join(fold, "..", "..", "_unittests")) - for nbf in explore_folder_iterfile(fold2, pattern=".*[.]ipynb"): - t = upgrade_notebook(nbf) - if t: - fLOG("modified", nbf) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_module/test_latex_translation.py b/_unittests/ut_module/test_latex_translation.py deleted file mode 100644 index 7e427eba..00000000 --- a/_unittests/ut_module/test_latex_translation.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -@brief test log(time=0s) -""" -import os -import unittest -import warnings -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import get_temp_folder, is_travis_or_appveyor - - -class TestLatexTranslation(unittest.TestCase): - - def test_translation(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - if is_travis_or_appveyor(): - warnings.warn("no pandoc") - return - from pyquickhelper.helpgen import latex2rst - temp = get_temp_folder(__file__, "temp_translation") - tex = os.path.join(temp, "..", "..", "..", "_todo") - for t in os.listdir(tex): - if ".tex" not in t: - continue - ft = os.path.join(tex, t) - to = os.path.join(temp, t.replace(".tex", ".rst")) - tom = os.path.join(temp, t.replace(".tex", ".rst.tmp")) - latex2rst(ft, to, encoding="latin-1", fLOG=fLOG, temp_file=tom) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_module/test_readme.py b/_unittests/ut_module/test_readme.py deleted file mode 100644 index c9d365b3..00000000 --- a/_unittests/ut_module/test_readme.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -@brief test tree node (time=50s) -""" -import os -import unittest -from pyquickhelper.loghelper import fLOG -from pyquickhelper.pycode import get_temp_folder - - -class TestReadme(unittest.TestCase): - - def test_venv_docutils08_readme(self): - fLOG( - __file__, - self._testMethodName, - OutputPrint=__name__ == "__main__") - - fold = os.path.dirname(os.path.abspath(__file__)) - readme = os.path.join(fold, "..", "..", "README.rst") - assert os.path.exists(readme) - with open(readme, "r", encoding="utf8") as f: - content = f.read() - - assert len(content) > 0 - temp = get_temp_folder(__file__, "temp_readme") - - if __name__ != "__main__": - # does not work from a virtual environment - return - - from pyquickhelper.pycode import check_readme_syntax - - check_readme_syntax(readme, folder=temp, fLOG=fLOG) - - -if __name__ == "__main__": - unittest.main() diff --git a/_unittests/ut_xrun_doc/test_documentation_examples.py b/_unittests/ut_xrun_doc/test_documentation_examples.py new file mode 100644 index 00000000..8856dbfc --- /dev/null +++ b/_unittests/ut_xrun_doc/test_documentation_examples.py @@ -0,0 +1,88 @@ +import unittest +import os +import sys +import importlib +import subprocess +import time +from teachpyx import __file__ as teachpyx_file +from teachpyx.ext_test_case import ExtTestCase + +VERBOSE = 0 +ROOT = os.path.realpath(os.path.abspath(os.path.join(teachpyx_file, "..", ".."))) + + +def import_source(module_file_path, module_name): + if not os.path.exists(module_file_path): + raise FileNotFoundError(module_file_path) + module_spec = importlib.util.spec_from_file_location(module_name, module_file_path) + if module_spec is None: + raise FileNotFoundError( + "Unable to find '{}' in '{}'.".format(module_name, module_file_path) + ) + module = importlib.util.module_from_spec(module_spec) + return module_spec.loader.exec_module(module) + + +class TestDocumentationExamples(ExtTestCase): + def run_test(self, fold: str, name: str, verbose=0) -> int: + ppath = os.environ.get("PYTHONPATH", "") + if len(ppath) == 0: + os.environ["PYTHONPATH"] = ROOT + elif ROOT not in ppath: + sep = ";" if sys.platform == "win32" else ":" + os.environ["PYTHONPATH"] = ppath + sep + ROOT + perf = time.perf_counter() + try: + mod = import_source(fold, os.path.splitext(name)[0]) + assert mod is not None + except FileNotFoundError: + # try another way + cmds = [sys.executable, "-u", os.path.join(fold, name)] + p = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + res = p.communicate() + out, err = res + st = err.decode("ascii", errors="ignore") + if len(st) > 0 and "Traceback" in st: + if '"dot" not found in path.' in st: + # dot not installed, this part + # is tested in onnx framework + if verbose: + print(f"failed: {name!r} due to missing dot.") + return -1 + if "No such file or directory: 'schema_pb2.py'" in str(st): + if verbose: + print( + f"failed: {name!r} due to missing protoc " + f"(or wrong version)." + ) + return -1 + raise AssertionError( + "Example '{}' (cmd: {} - exec_prefix='{}') " + "failed due to\n{}" + "".format(name, cmds, sys.exec_prefix, st) + ) + dt = time.perf_counter() - perf + if verbose: + print(f"{dt:.3f}: run {name!r}") + return 1 + + @classmethod + def add_test_methods(cls): + this = os.path.abspath(os.path.dirname(__file__)) + fold = os.path.normpath(os.path.join(this, "..", "..", "_doc", "examples")) + found = os.listdir(fold) + for name in found: + if name.startswith("plot_") and name.endswith(".py"): + short_name = os.path.split(os.path.splitext(name)[0])[-1] + + def _test_(self, name=name): + res = self.run_test(fold, name, verbose=VERBOSE) + self.assertIn(res, (-1, 1)) + + setattr(cls, f"test_{short_name}", _test_) + + +TestDocumentationExamples.add_test_methods() + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/appveyor.yml b/appveyor.yml index 340b8bcb..e8ed747f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,11 +11,11 @@ init: install: - "%PYTHON%\\python -m pip install --upgrade pip" - "%PYTHON%\\Scripts\\pip install -r requirements.txt" - - set PYTHONPATH=src + - "%PYTHON%\\Scripts\\pip install -r requirements-dev.txt" build: off test_script: - - "%PYTHON%\\python -u setup.py unittests" + - "%PYTHON%\\python -m pytest _unittests" after_test: - "%PYTHON%\\python -u setup.py bdist_wheel" diff --git a/build_script.bat b/build_script.bat deleted file mode 100644 index b92257b0..00000000 --- a/build_script.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off -if "%1"=="" goto default_value_python: -set pythonexe="%1" -%pythonexe% setup.py write_version -goto custom_python: - -:default_value_python: -set pythonexe="c:\Python391_x64\python.exe" -if not exist %pythonexe% set pythonexe="c:\Python372_x64\python.exe" -:custom_python: -@echo [python] %pythonexe% -%pythonexe% -u setup.py build_script -if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..8763799c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,54 @@ +[tool.rstcheck] +report_level = "INFO" +ignore_directives = [ + "autosignature", + "autoclass", + "autofunction", + "automodule", + "blockdiag", + "blogpost", + "blogpostagg", + "exref", + "exreflist", + "faqref", + "faqreflist", + "gdot", + "image-sg", + "inheritance-diagram", + "mathdef", + "mathdeflist", + "nbgallery", + "nbgallerylink", + "plot", + "runpython", + "tocdelay", +] +ignore_roles = ["epkg", "githublink", "issue"] +ignore_messages = [ + ".*Hyperlink target .* is not referenced.*", + ".*Document or section may not begin with a transition.*", + ".*Unknown target name: .*[0-9]{4}.*", + ".*Duplicate explicit target name: .pdf..*", + ".*Unexpected possible title overline or transition..*", +] + +[tool.ruff] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".eggs", + ".git", + "build", + "dist", +] + +# Same as Black. +line-length = 88 + +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 10 + +[tool.ruff.per-file-ignores] +"_doc/conf.py" = ["F821"] +"teachpyx/__init__.py" = ["E501"] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000..79667a8a --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,25 @@ +black +black-nb +blockdiag +cloudpickle +coverage +jupyter +matplotlib +mutagen # mp3 +nbsphinx +pandas +pillow +protobuf<4 +pydata_sphinx_theme +pytest +pytest-cov +ruff +scikit-learn>=1.2 +sphinx +sphinx-gallery +sphinx-issues +sphinxcontrib-blockdiag +git+https://github.com/sdpython/sphinx-runpython.git +tqdm +ujson +wheel diff --git a/requirements.txt b/requirements.txt index 26c544fa..46c38e1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,32 +1,3 @@ -bokeh -cloudpickle -coverage -ipython -jupyter -jupyter_client -jupyter_core -jyquickhelper matplotlib -mutagen -numpy>=1.11.0 -nbformat -nbpresent -notebook>=5.0.0 -pandas>=1.0.0 -pandas_streaming>=0.1.87 -pillow -protobuf -pycodestyle -pylint>=2.14.0 -pyquickhelper>=1.9 -pyquicksetup>=0.2 -scikit-learn -scipy -sphinx -sphinxcontrib.imagesvg -pydata_sphinx_theme -sphinxcontrib-blockdiag -sphinx_gallery -solar-theme -ujson -wheel +numpy +pandas diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..cbf5a663 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[options] +packages = find: + +[options.packages.find] +include = teachpyx* diff --git a/setup.py b/setup.py index 8c092fb9..cdd6defb 100644 --- a/setup.py +++ b/setup.py @@ -1,61 +1,66 @@ # -*- coding: utf-8 -*- -import sys import os -from setuptools import find_packages, setup -from pyquicksetup import read_version, read_readme, default_cmdclass +from setuptools import setup -######### -# settings -######### +###################### +# beginning of setup +###################### -project_var_name = "teachpyx" -versionPython = f"{sys.version_info.major}.{sys.version_info.minor}" -path = "Lib/site-packages/" + project_var_name -readme = 'README.rst' -history = "HISTORY.rst" -requirements = None -KEYWORDS = [project_var_name, 'Xavier Dupré', 'teaching'] -DESCRIPTION = """Lectures about programming mostly in Python.""" +here = os.path.dirname(__file__) +if here == "": + here = "." +package_data = {"teachpyx": ["*.txt"]} +try: + with open(os.path.join(here, "requirements.txt"), "r") as f: + requirements = f.read().strip(" \n\r\t").split("\n") +except FileNotFoundError: + requirements = [] +if len(requirements) == 0 or requirements == [""]: + requirements = ["matplotlib", "numpy", "pandas"] -CLASSIFIERS = [ - 'Programming Language :: Python :: %d' % sys.version_info[0], - 'Intended Audience :: Developers', - 'Topic :: Scientific/Engineering', - 'Topic :: Education', - 'License :: OSI Approved :: MIT License', - 'Development Status :: 5 - Production/Stable' -] - - -####### -# data -####### - - -packages = find_packages('src', exclude='src') -package_dir = {k: "src/" + k.replace(".", "/") for k in packages} -package_data = {} +try: + with open(os.path.join(here, "README.rst"), "r", encoding="utf-8") as f: + long_description = "teachpyx:" + f.read().split("teachpyx:")[1] +except FileNotFoundError: + long_description = "" +version_str = "0.1.0" +with open(os.path.join(here, "teachpyx/__init__.py"), "r") as f: + line = [ + _ + for _ in [_.strip("\r\n ") for _ in f.readlines()] + if _.startswith("__version__") + ] + if len(line) > 0: + version_str = line[0].split("=")[1].strip('" ') +# see https://pypi.org/classifiers/ setup( - name=project_var_name, - version=read_version(__file__, project_var_name, subfolder='src'), - author='Xavier Dupré', - author_email='xavier.dupre@gmail.com', - license="MIT", - url="http://www.xavierdupre.fr/app/teachpyx/helpsphinx/index.html", - download_url="https://github.com/sdpython/teachpyx/", - description=DESCRIPTION, - long_description=read_readme(__file__), - cmdclass=default_cmdclass(), - keywords=KEYWORDS, - classifiers=CLASSIFIERS, - packages=packages, - package_dir=package_dir, + name="teachpyx", + version=version_str, + description="Programmation Python", + long_description=long_description, + author="Xavier Dupré", + author_email="xavier.dupre@gmail.com", + url="https://github.com/sdpython/teachpyx", package_data=package_data, - setup_requires=['pyquicksetup>=0.2'], - install_requires=['numpy>=1.18', 'pandas>=1.0'], + install_requires=requirements, + classifiers=[ + "Intended Audience :: Science/Research", + "Intended Audience :: Education", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Mathematics", + "Topic :: Education", + "Development Status :: 5 - Production/Stable", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + ], ) diff --git a/src/teachpyx/__init__.py b/src/teachpyx/__init__.py deleted file mode 100644 index fc4def5a..00000000 --- a/src/teachpyx/__init__.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -""" -@file -@brief Module *teachpyx*. -Materials for a book about programming with :epkg:`Python`. -""" - -__version__ = "0.2.335" -__author__ = "Xavier Dupré" -__github__ = "https://github.com/sdpython/teachpyx" -__url__ = "http://www.xavierdupre.fr/app/teachpyx/helpsphinx/index.html" -__license__ = "MIT License" -__blog__ = """ - - - - blog - - - - - -""" - - -def check(log=False): - """ - Checks the library is working. - It raises an exception. - If you want to disable the logs: - - @param log if True, display information, otherwise - @return 0 or exception - """ - return True - - -def _setup_hook(use_print=False): - """ - if this function is added to the module, - the help automation and unit tests call it first before - anything goes on as an initialization step. - """ - # we can check many things, needed module - # any others things before unit tests are started - if use_print: - print("Success: _setup_hook") diff --git a/src/teachpyx/faq/__init__.py b/src/teachpyx/faq/__init__.py deleted file mode 100644 index dd9c5882..00000000 --- a/src/teachpyx/faq/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" -@file -@breif shortcuts for FAQ -""" - -from .faq_python import enumerate_regex_search diff --git a/teachpyx/__init__.py b/teachpyx/__init__.py new file mode 100644 index 00000000..c7d881ba --- /dev/null +++ b/teachpyx/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +""" +@file +@brief Module *teachpyx*. +Materials for a book about programming with :epkg:`Python`. +""" + +__version__ = "0.3.0" +__author__ = "Xavier Dupré" +__github__ = "https://github.com/sdpython/teachpyx" +__url__ = "https://sdpython.github.io/doc/teachpyx/dev/" +__license__ = "MIT License" diff --git a/src/teachpyx/examples/__init__.py b/teachpyx/examples/__init__.py similarity index 100% rename from src/teachpyx/examples/__init__.py rename to teachpyx/examples/__init__.py diff --git a/src/teachpyx/examples/classiques.py b/teachpyx/examples/classiques.py similarity index 81% rename from src/teachpyx/examples/classiques.py rename to teachpyx/examples/classiques.py index d8314c0d..fbbe24b1 100644 --- a/src/teachpyx/examples/classiques.py +++ b/teachpyx/examples/classiques.py @@ -17,18 +17,20 @@ def commentaire_accentues(): :tag: python :title: Python n'accepte pas les accents - .. index:: accent, accents, utf8, encoding - - Le langage Python a été conçu en langage anglais. Dès qu'on on ajoute un caractère - qui ne fait pas partie de l'alphabet anglais (ponctuation comprise), il déclenche une erreur : + Le langage Python a été conçu en langage anglais. + Dès qu'on on ajoute un caractère + qui ne fait pas partie de l'alphabet anglais + (ponctuation comprise), il déclenche une erreur : :: File "faq_cvxopt.py", line 3 - SyntaxError: Non-UTF-8 code starting with '\xe8' in file faq_cvxopt.py on line 4, but no encoding declared; + SyntaxError: Non-UTF-8 code starting with '\xe8' in + file faq_cvxopt.py on line 4, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details - Pour la résoudre, il faut dire à l'interpréteur que des caractères non anglais peuvent apparaître + Pour la résoudre, il faut dire à l'interpréteur que + des caractères non anglais peuvent apparaître et écrire sur la première ligne du programme : :: @@ -41,12 +43,14 @@ def commentaire_accentues(): # -*- coding: utf-8 -*- - Si vous utilisez l'éditeur `SciTE `_ sous Windows, + Si vous utilisez l'éditeur + `SciTE `_ sous Windows, après avoir ajouté cette ligne avec l'encoding `utf-8`, il est conseillé de fermer le fichier puis de le réouvrir. SciTE le traitera différemment. - **L'encodage ``utf-8`` est la norme sur Internet.** C'est pourquoi il est préférable d'utiliser celui-ci pour + **L'encodage ``utf-8`` est la norme sur Internet.** + C'est pourquoi il est préférable d'utiliser celui-ci pour partager son code via une page Web. """ pass @@ -91,7 +95,7 @@ def dix_entiers_carre(): """ s = 0 for i in range(1, 11): - s += i ** 2 + s += i**2 return s @@ -116,8 +120,10 @@ def variance_a_eviter(serie): s += (obs-moyenne(serie))**2 return s / len(serie) - La fonction ``variance_a_eviter`` appelle la fonction ``moyenne`` à chaque passage - dans la boucle. Or, rien ne change d'un passage à l'autre. Il vaut mieux stocker + La fonction ``variance_a_eviter`` + appelle la fonction ``moyenne`` à chaque passage + dans la boucle. Or, rien ne change d'un passage à l'autre. + Il vaut mieux stocker le résultat dans une variable : :: @@ -203,8 +209,8 @@ def dictionnaire_modifie_dans_la_boucle(): for k,v in d.items(): RuntimeError: dictionary changed size during iteration - Il faut pour éviter cela stocker les éléments qu'on veut modifier pour les supprimer - ensuite. + Il faut pour éviter cela stocker les éléments + qu'on veut modifier pour les supprimer ensuite. :: @@ -217,7 +223,8 @@ def dictionnaire_modifie_dans_la_boucle(): del d[r] Même si Python autorise cela pour les listes, - il est conseillé de s'en abstenir ainsi que pour tout type d'objets qui en contient d'autres. + il est conseillé de s'en abstenir ainsi que pour tout + type d'objets qui en contient d'autres. C'est une habitude qui vous servira pour la plupart des autres langages. """ liste = [0, 1, 2, 3, 4, 5, 6] @@ -240,17 +247,18 @@ def str2date(s, format="%d/%m/%Y"): """ convertit une chaîne de caractères en datetime - @param s chaîne de caractères - @param format format de la conversion - + :param s: chaîne de caractères + :param format: format de la conversion .. exref:: :title: conversion d'une chaîne de caractère en datetime :tag: Base - C'est le genre de fonction qu'on n'utilise pas souvent mais qu'on peine à retrouver + C'est le genre de fonction qu'on n'utilise pas souvent + mais qu'on peine à retrouver lorsqu'on en a besoin. - Il faut utiliser la fonction `strftime `_. + Il faut utiliser la fonction `strftime + `_. :: diff --git a/src/teachpyx/examples/construction_classique.py b/teachpyx/examples/construction_classique.py similarity index 70% rename from src/teachpyx/examples/construction_classique.py rename to teachpyx/examples/construction_classique.py index c4112189..43fd2677 100644 --- a/src/teachpyx/examples/construction_classique.py +++ b/teachpyx/examples/construction_classique.py @@ -1,9 +1,5 @@ -# -*- coding: utf-8 -*- -""" -@file -@brief Quelques constructions classiques pour éviter de recoder des variantes d'algorithmes. -classiques. -""" +# coding: utf-8 + from functools import reduce @@ -12,9 +8,9 @@ def recherche(li, c): """ Retourne l'index d'un élément ou -1 si non trouvé. - @param li liste - @param c élément à trouver - @return position + :param li: liste + :param c: élément à trouver + :return: position .. exref:: :tag: Base @@ -50,9 +46,12 @@ def recherche (li, c) : else: return -1 - Même si ce bout de code parcourt deux fois le tableau (une fois déterminer - sa présence, une seconde fois pour sa position), ce code est souvent plus rapide - que la première version et la probabilité d'y faire une erreur plus faible. + Même si ce bout de code parcourt deux fois le + tableau (une fois déterminer + sa présence, une seconde fois pour sa position), + ce code est souvent plus rapide + que la première version et la probabilité + d'y faire une erreur plus faible. """ if c in li: return li.index(c) @@ -64,17 +63,18 @@ def minindex(li): """ Retourne l'index du minimum et le minimum. - @param li liste - @return tuple (minimum,position) - + :param li: liste + :return: tuple (minimum, position) .. exref:: :tag: Base :title: minimum avec position - La fonction `min `_ + La fonction `min + `_ retourne le minium d'un tableau mais pas sa position. - Le premier réflexe est alors de recoder le parcours de la liste + Le premier réflexe est alors de recoder le + parcours de la liste tout en conservant la position du minimum. .. runpython:: @@ -87,7 +87,8 @@ def minindex(li): m = i print(m) - Mais il existe une astuce pour obtenir la position sans avoir à le reprogrammer. + Mais il existe une astuce pour obtenir la + position sans avoir à le reprogrammer. .. runpython:: :showcode: @@ -97,7 +98,8 @@ def minindex(li): m = min(k) print(m) - La fonction ``min`` choisit l'élément minimum d'un tableau dont les éléments sont des + La fonction ``min`` choisit l'élément minimum d'un + tableau dont les éléments sont des couples (élément du premier tableau, sa position). Le minimum est choisi en comparant les éléments, et la position départegera les exaequo. @@ -109,9 +111,9 @@ def recherche_dichotomique(li, c): """ Effectue une recherche dichotomique. - @param li tableau - @param c élément à chercher - @return position + :param li: tableau + :param c: élément à chercher + :return: position .. exref:: :tag: Base @@ -120,9 +122,12 @@ def recherche_dichotomique(li, c): La `recherche dichotomique `_ est plus rapide qu'une recherche classique mais elle suppose que celle-ci s'effectue dans un ensemble trié. - L'idée est de couper en deux l'intervalle de recherche à chaque itération. - Comme l'ensemble est trié, en comparant l'élément cherché à l'élément central, - on peut éliminer une partie de l'ensemble : la moitié inférieure ou supérieure. + L'idée est de couper en deux l'intervalle de + recherche à chaque itération. + Comme l'ensemble est trié, en comparant + l'élément cherché à l'élément central, + on peut éliminer une partie de l'ensemble : + la moitié inférieure ou supérieure. .. runpython:: :showcode: @@ -144,30 +149,34 @@ def recherche_dichotomique(li, c) : if c == li[m]: return m elif c < li[m]: - b = m - 1 # partie supérieure éliminée + b = m - 1 # partie supérieure éliminée else: - a = m + 1 # partie inférieure éliminée + a = m + 1 # partie inférieure éliminée return -1 # élément non trouvé def text2mat(s, sep_row="\n", sep_col="\t"): """ - Convertit une chaîne de caractères en une matrice ( = liste de listes), + Convertit une chaîne de caractères en une matrice + ( = liste de listes), réciproque de la fonction @see fn mat2text. - @param s texte à convertir - @param sep_row séparation de ligne - @param sep_col séparateur de colonnes - @return liste de liste + :param s: texte à convertir + :param sep_row: séparation de ligne + :param sep_col: séparateur de colonnes + :return: liste de liste .. exref:: :tag: Base :title: conversion d'une chaîne de caractère en matrice - Les quelques lignes qui suivent permettent de décomposer une chaîne de caractères + Les quelques lignes qui suivent permettent de décomposer + une chaîne de caractères en matrice. Chaque ligne et chaque colonne sont séparées par des - séparateurs différents. Ce procédé intervient souvent lorsqu'on récupère des - informations depuis un fichier texte lui-même provenant d'un tableur. + séparateurs différents. Ce procédé intervient souvent + lorsqu'on récupère des + informations depuis un fichier texte lui-même provenant + d'un tableur. .. runpython:: :showcode: @@ -181,15 +190,21 @@ def text2mat(s, sep_row="\n", sep_col="\t"): Comme cette opération est très fréquente lorsqu'on travaille avec les données, on ne l'implémente plus soi-même. On préfère utiliser un module comme - `pandas `_ qui est plus robuste et considère plus de cas. - Pour écrire, utilise la méthode `to_csv `_, + `pandas `_ qui est plus + robuste et considère plus de cas. + Pour écrire, utilise la méthode `to_csv + `_, pour lire, la fonction - `read_csv `_. + `read_csv + `_. On peut également directement enregistrer au format Excel - `read_excel `_ et écrire dans ce même format - `to_excel `_. + `read_excel + `_ + et écrire dans ce même format + `to_excel + `_. """ - ligne = s.split(sep_row) # lignes + ligne = s.split(sep_row) # lignes mat = [el.split(sep_col) for el in ligne] # colonnes return mat @@ -199,10 +214,10 @@ def mat2text(mat, sep_row="\n", sep_col="\t"): Convertit une matrice en une chaîne de caractères, réciproque de la fonction @see fn text2mat. - @param mat matrice à convertir (liste de listes) - @param sep_row séparation de ligne - @param sep_col séparateur de colonnes - @return liste de liste + :param mat: matrice à convertir (liste de listes) + :param sep_row: séparation de ligne + :param sep_col: séparateur de colonnes + :return: liste de liste .. exref:: :tag: Base @@ -217,8 +232,8 @@ def mat2text(mat, sep_row="\n", sep_col="\t"): print(s) """ - ligne = [";".join(li) for li in mat] # colonnes - s = "|".join(ligne) # lignes + ligne = [";".join(li) for li in mat] # colonnes + s = "|".join(ligne) # lignes return s @@ -226,14 +241,15 @@ def somme(li): """ Calcule la somme des éléments d'un tableau. - @param li tableau - @return somme + :param li: tableau + :return: somme .. exref:: :tag: Base :title: calcul d'une somme - Le calcul d'une somme fait toujours intervenir une boucle car le langage + Le calcul d'une somme fait toujours + intervenir une boucle car le langage :epkg:`Python` ne peut faire des additions qu'avec deux nombres. Le schéma est toujours le même : initialisation et boucle. @@ -246,8 +262,10 @@ def somme(li): s += l # addition print(s) - Ce code est équivalent à la fonction `sum `_. - Dans ce cas où la somme intègre le résultat d'une fonction (au sens mathématique) + Ce code est équivalent à la fonction `sum + `_. + Dans ce cas où la somme intègre le résultat d'une fonction + (au sens mathématique) et non les éléments d'une liste, il faudrait écrire : .. runpython:: @@ -262,7 +280,8 @@ def fonction(x): s += fonction (l) print(s) - Et ces deux lignes pourraient être résumées en une seule grâce + Et ces deux lignes pourraient être résumées + en une seule grâce à l'une de ces instructions : .. runpython:: @@ -279,7 +298,8 @@ def fonction(x): L'avantage des deux dernières instructions est qu'elles évitent la création d'une liste intermédiaire, - c'est un point à prendre en compte si la liste sur laquelle opère la + c'est un point à prendre en compte si la + liste sur laquelle opère la somme est volumineuse. """ return sum(li) @@ -289,15 +309,17 @@ def triindex(li): """ Trie une liste, retourne la liste triée et les positions initiales. - @param li tableau - @return liste triée + :param li: tableau + :return: liste triée .. exref:: :tag: Base :title: tri, garder les positions initiales - Le tri est une opération fréquente. On n'a pas toujours le temps de programmer - le tri le plus efficace comme un tri `quicksort `_ + Le tri est une opération fréquente. On n'a pas + toujours le temps de programmer + le tri le plus efficace comme un tri `quicksort + `_ et un tri plus simple suffit la plupart du temps. Le tri suivant consiste à recherche le plus petit élément puis à échanger sa place avec le premier élément du tableau du tableau. @@ -321,15 +343,20 @@ def triindex(li): print(li) - La fonction `sorted `_ + La fonction `sorted + `_ trie également une liste mais selon un algorithme plus efficace que celui-ci (voir `Timsort `_). - On est parfois amené à reprogrammer un tri parce qu'on veut conserver la position des éléments + On est parfois amené à reprogrammer un tri parce qu'on veut + conserver la position des éléments dans le tableau non trié. - Cela arrive quand on souhaite trier un tableau et appliquer la même transformation à un second + Cela arrive quand on souhaite trier un tableau et + appliquer la même transformation à un second tableau. - Il est toujours préférable de ne pas reprogrammer un tri (moins d'erreur). - Il suffit d'applicer la même idée que pour la fonction @see fn minindex. + Il est toujours préférable de ne pas reprogrammer + un tri (moins d'erreur). + Il suffit d'applicer la même idée que pour la + fonction @see fn minindex. .. runpython:: :showcode: @@ -355,16 +382,18 @@ def compte(li): """ Compte le nombre d'occurrences de chaque élément d'une liste. - @param li tableau - @return dictionnaire + :param li: tableau + :return: dictionnaire .. exref:: :tag: Base :title: comptage - :lid: l-ex-comptage + :label: l-ex-comptage - On souhaite ici compter le nombre d'occurrences de chaque élément d'un tableau. - Par exemple, on pourrait connaître par ce moyen la popularité d'un mot dans un discours + On souhaite ici compter le nombre d'occurrences de + chaque élément d'un tableau. + Par exemple, on pourrait connaître par ce moyen + la popularité d'un mot dans un discours politique ou l'étendue du vocabulaire utilisé. L'exemple suivant compte les mots d'une liste de mots. @@ -380,11 +409,14 @@ def compte(li): d[l] += 1 print(d) # affiche {'un': 2, 'trois': 1, 'deux': 1} - La structure la plus appropriée ici est un dictionnaire puisqu'on cherche + La structure la plus appropriée ici est un + dictionnaire puisqu'on cherche à associer une valeur à un élément d'une liste qui peut être de tout type. Si la liste contient des éléments de type modifiable comme une liste, - il faudrait convertir ceux-ci en un type immuable comme une chaîne de caractères. - L'exemple suivant illustre ce cas en comptant les occurrences des lignes d'une matrice. + il faudrait convertir ceux-ci en un type immuable + comme une chaîne de caractères. + L'exemple suivant illustre ce cas en comptant + les occurrences des lignes d'une matrice. .. runpython:: :showcode: @@ -400,10 +432,13 @@ def compte(li): print(d) # affiche {'[1, 1, 1]': 2, '[2, 2, 2]': 1} Les listes ne peuvent pas être les clés du dictionnaire : - `Why Lists Can't Be Dictionary Keys `_. + `Why Lists Can't Be Dictionary Keys + `_. - On peut également vouloir non pas compter le nombre d'occurrence mais mémoriser les - positions des éléments tous identiques. On doit utiliser un dictionnaire de listes : + On peut également vouloir non pas compter + le nombre d'occurrence mais mémoriser les + positions des éléments tous identiques. + On doit utiliser un dictionnaire de listes : .. runpython:: :showcode: @@ -439,16 +474,19 @@ def mat2vect(mat): Convertit une matrice en un tableau à une seule dimension, réciproque de la fonction @see fn vect2mat. - @param mat matrice - @return liste + :param mat: matrice + :return: liste .. exref:: :tag: Base :title: conversion d'une matrice en un vecteur - Dans un langage comme le *C++*, il arrive fréquemment qu'une matrice ne soit pas - représentée par une liste de listes mais par une seule liste car cette représentation - est plus efficace. Il faut donc convertir un indice en deux indices ligne et colonne. + Dans un langage comme le *C++*, il arrive fréquemment + qu'une matrice ne soit pas + représentée par une liste de listes mais par une seule + liste car cette représentation + est plus efficace. Il faut donc convertir un indice + en deux indices ligne et colonne. Il faut bien sûr que le nombre de colonnes sur chaque ligne soit constant. Le premier programme convertit une liste de listes en une seule liste. @@ -480,19 +518,24 @@ def vect2mat(vect, ncol): Convertit un tableau à une dimension en une matrice, réciproque de la fonction @see fn mat2vect. - @param vect vecteur - @param ncol nombre de colonnes - @return matrice + :param vect: vecteur + :param ncol: nombre de colonnes + :return: matrice .. exref:: :tag: Base :title: conversion d'un vecteur en une matrice - Dans un langage comme le *C++*, il arrive fréquemment qu'une matrice ne soit pas - représentée par une liste de listes mais par une seule liste car cette représentation - est plus efficace. Il faut donc convertir un indice en deux indices ligne et colonne. - Il faut bien sûr que le nombre de colonnes sur chaque ligne soit constant. - Le premier programme convertit une liste de listes en une seule liste. + Dans un langage comme le *C++*, il arrive fréquemment + qu'une matrice ne soit pas + représentée par une liste de listes mais par une + seule liste car cette représentation + est plus efficace. Il faut donc convertir un + indice en deux indices ligne et colonne. + Il faut bien sûr que le nombre de colonnes sur + chaque ligne soit constant. + Le premier programme convertit une liste de + listes en une seule liste. .. runpython:: :showcode: @@ -503,8 +546,7 @@ def vect2mat(vect, ncol): print(mat) """ - return [vect[i * ncol: (i + 1) * ncol] - for i in range(0, len(vect) // ncol)] + return [vect[i * ncol : (i + 1) * ncol] for i in range(0, len(vect) // ncol)] def integrale(fonction, a, b, n): @@ -512,16 +554,16 @@ def integrale(fonction, a, b, n): Calcule l'intégrale d'une fonction avec la `méthode de Rienmann `_. - @param fonction fonction - @param a borne inférieure de l'intervalle - @param b borne supérieure de l'intervalle - @param n nombre de division de l'intervalle - @return valeur + :param fonction: fonction + :param a: borne inférieure de l'intervalle + :param b: borne supérieure de l'intervalle + :param n: nombre de division de l'intervalle + :return: valeur .. exref:: :tag: Base :title: fonction comme paramètre - :lid: paragraphe_fonction_variable + :label: paragraphe_fonction_variable Une fonction peut aussi recevoir en paramètre une autre fonction. L'exemple suivant inclut la fonction ``calcul_n_valeur`` @@ -562,7 +604,7 @@ def construit_matrice_carree(n): Cette fonction construit une matrice carrée remplie de zéro sous la forme d'une liste de listes. - @param n dimension de la matrice carrée + :param n: dimension de la matrice carrée """ return [[0 for i in range(n)] for j in range(n)] @@ -571,8 +613,8 @@ def enumerate_permutations_recursive(ensemble): """ Enumère les permutations d'un ensemble de façon récursive. - @param ensemble ensemble à permuter - @return itérateur sur les permutations + :param ensemble: ensemble à permuter + :return: itérateur sur les permutations """ if len(ensemble) == 1: @@ -590,15 +632,14 @@ def enumerate_permutations(ensemble): """ Enumère les permutations d'un ensemble de façon non récursive. - @param ensemble ensemble à permuter - @return itérateur sur les permutations + :param ensemble: ensemble à permuter + :return: itérateur sur les permutations """ if len(ensemble) == 1: yield ensemble else: position = list(range(len(ensemble))) while position[0] < len(ensemble): - memo = [] for i, p in enumerate(position): ensemble[i], ensemble[p] = ensemble[p], ensemble[i] diff --git a/src/teachpyx/examples/numpysex.py b/teachpyx/examples/numpysex.py similarity index 78% rename from src/teachpyx/examples/numpysex.py rename to teachpyx/examples/numpysex.py index f5fff582..f4e1dc5b 100644 --- a/src/teachpyx/examples/numpysex.py +++ b/teachpyx/examples/numpysex.py @@ -10,8 +10,8 @@ def numpy_matrix2list(mat): """ Convertit une matrice `numpy `_ en list. - @param mat matrix - @return liste de listes + :param mat: matrix + :return: liste de listes .. exref:: :title: opérations avec numpy.matrix @@ -64,7 +64,8 @@ def numpy_types(): :title: Quels sont les types que numpy supporte ? :tag: numpy - Lire `basic types `_. + Lire `basic types + `_. `numpy `_ propose plus de types que Python, les mêmes que le langage C (langage de son implémentation). Les programmeurs cherchent toujours @@ -73,27 +74,31 @@ def numpy_types(): on peut utiliser le type *numpy.uint8* qui est codé sur un octet. Cela explique pourquoi beaucoup de libraires de machine learning sont codées des *numpy.float32*, soit 4 octets plutôt que *numpy.float64* ou *double*. - Deux raisons à cela, les *numpy.float32* prennent deux fois moins de place en mémoire. + Deux raisons à cela, les *numpy.float32* prennent deux fois + moins de place en mémoire. Le coût des calculs avec des *double* est plus coûteux avec les GPU. - Lire `Explaining FP64 performance on GPUs `_. + Lire `Explaining FP64 performance on GPUs + `_. """ - return [numpy.bool_, - numpy.int_, - numpy.intc, - numpy.intp, - numpy.int8, - numpy.int16, - numpy.int32, - numpy.int64, - numpy.uint8, - numpy.uint16, - numpy.uint32, - numpy.uint64, - numpy.float_, - numpy.float16, - numpy.float32, - numpy.float64, - numpy.complex_, - numpy.complex64, - numpy.complex128] + return [ + numpy.bool_, + numpy.int_, + numpy.intc, + numpy.intp, + numpy.int8, + numpy.int16, + numpy.int32, + numpy.int64, + numpy.uint8, + numpy.uint16, + numpy.uint32, + numpy.uint64, + numpy.float_, + numpy.float16, + numpy.float32, + numpy.float64, + numpy.complex_, + numpy.complex64, + numpy.complex128, + ] diff --git a/teachpyx/ext_test_case.py b/teachpyx/ext_test_case.py new file mode 100644 index 00000000..125e309a --- /dev/null +++ b/teachpyx/ext_test_case.py @@ -0,0 +1,326 @@ +import os +import sys +import unittest +import warnings +from argparse import ArgumentParser +from contextlib import redirect_stderr, redirect_stdout +from io import StringIO +from timeit import Timer +from typing import Any, Callable, Dict, List, Optional, Tuple, Union + +import numpy +from numpy.testing import assert_allclose + + +def unit_test_going(): + """ + Enables a flag telling the script is running while testing it. + Avois unit tests to be very long. + """ + going = int(os.environ.get("UNITTEST_GOING", 0)) + return going == 1 + + +def ignore_warnings(warns: List[Warning]) -> Callable: + """ + Catches warnings. + + :param warns: warnings to ignore + """ + + def wrapper(fct): + if warns is None: + raise AssertionError(f"warns cannot be None for '{fct}'.") + + def call_f(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", warns) + return fct(self) + + return call_f + + return wrapper + + +def measure_time( + stmt: Union[str, Callable], + context: Optional[Dict[str, Any]] = None, + repeat: int = 10, + number: int = 50, + warmup: int = 1, + div_by_number: bool = True, + max_time: Optional[float] = None, +) -> Dict[str, Any]: + """ + Measures a statement and returns the results as a dictionary. + + :param stmt: string or callable + :param context: variable to know in a dictionary + :param repeat: average over *repeat* experiment + :param number: number of executions in one row + :param warmup: number of iteration to do before starting the + real measurement + :param div_by_number: divide by the number of executions + :param max_time: execute the statement until the total goes + beyond this time (approximatively), *repeat* is ignored, + *div_by_number* must be set to True + :return: dictionary + + .. runpython:: + :showcode: + + from onnx_extended.ext_test_case import measure_time + from math import cos + + res = measure_time(lambda: cos(0.5)) + print(res) + + See `Timer.repeat `_ + for a better understanding of parameter *repeat* and *number*. + The function returns a duration corresponding to + *number* times the execution of the main statement. + + .. versionchanged:: 0.4 + Parameter *max_time* was added. + """ + if not callable(stmt) and not isinstance(stmt, str): + raise TypeError( + f"stmt is not callable or a string but is of type {type(stmt)!r}." + ) + if context is None: + context = {} + + if isinstance(stmt, str): + tim = Timer(stmt, globals=context) + else: + tim = Timer(stmt) + + if warmup > 0: + warmup_time = tim.timeit(warmup) + else: + warmup_time = 0 + + if max_time is not None: + if not div_by_number: + raise ValueError( + "div_by_number must be set to True of max_time is defined." + ) + i = 1 + total_time = 0 + results = [] + while True: + for j in (1, 2): + number = i * j + time_taken = tim.timeit(number) + results.append((number, time_taken)) + total_time += time_taken + if total_time >= max_time: + break + if total_time >= max_time: + break + ratio = (max_time - total_time) / total_time + ratio = max(ratio, 1) + i = int(i * ratio) + + res = numpy.array(results) + tw = res[:, 0].sum() + ttime = res[:, 1].sum() + mean = ttime / tw + ave = res[:, 1] / res[:, 0] + dev = (((ave - mean) ** 2 * res[:, 0]).sum() / tw) ** 0.5 + mes = dict( + average=mean, + deviation=dev, + min_exec=numpy.min(ave), + max_exec=numpy.max(ave), + repeat=1, + number=tw, + ttime=ttime, + ) + else: + res = numpy.array(tim.repeat(repeat=repeat, number=number)) + if div_by_number: + res /= number + + mean = numpy.mean(res) + dev = numpy.mean(res**2) + dev = (dev - mean**2) ** 0.5 + mes = dict( + average=mean, + deviation=dev, + min_exec=numpy.min(res), + max_exec=numpy.max(res), + repeat=repeat, + number=number, + ttime=res.sum(), + ) + + if "values" in context: + if hasattr(context["values"], "shape"): + mes["size"] = context["values"].shape[0] + else: + mes["size"] = len(context["values"]) + else: + mes["context_size"] = sys.getsizeof(context) + mes["warmup_time"] = warmup_time + return mes + + +class ExtTestCase(unittest.TestCase): + _warns = [] + + def assertExists(self, name): + if not os.path.exists(name): + raise AssertionError(f"File or folder {name!r} does not exists.") + + def assertEqualArray( + self, + expected: numpy.ndarray, + value: numpy.ndarray, + atol: float = 0, + rtol: float = 0, + ): + self.assertEqual(expected.dtype, value.dtype) + self.assertEqual(expected.shape, value.shape) + assert_allclose(expected, value, atol=atol, rtol=rtol) + + def assertAlmostEqual( + self, + expected: numpy.ndarray, + value: numpy.ndarray, + atol: float = 0, + rtol: float = 0, + ): + if not isinstance(expected, numpy.ndarray): + expected = numpy.array(expected) + if not isinstance(value, numpy.ndarray): + value = numpy.array(value).astype(expected.dtype) + self.assertEqualArray(expected, value, atol=atol, rtol=rtol) + + def assertRaise(self, fct: Callable, exc_type: Exception): + try: + fct() + except exc_type as e: + if not isinstance(e, exc_type): + raise AssertionError(f"Unexpected exception {type(e)!r}.") + return + raise AssertionError("No exception was raised.") + + def assertEmpty(self, value: Any): + if value is None: + return + if len(value) == 0: + return + raise AssertionError(f"value is not empty: {value!r}.") + + def assertNotEmpty(self, value: Any): + if value is None: + raise AssertionError(f"value is empty: {value!r}.") + if isinstance(value, (list, dict, tuple, set)): + if len(value) == 0: + raise AssertionError(f"value is empty: {value!r}.") + + def assertStartsWith(self, prefix: str, full: str): + if not full.startswith(prefix): + raise AssertionError(f"prefix={prefix!r} does not start string {full!r}.") + + @classmethod + def tearDownClass(cls): + for name, line, w in cls._warns: + warnings.warn(f"\n{name}:{line}: {type(w)}\n {str(w)}") + + def capture(self, fct: Callable): + """ + Runs a function and capture standard output and error. + + :param fct: function to run + :return: result of *fct*, output, error + """ + sout = StringIO() + serr = StringIO() + with redirect_stdout(sout): + with redirect_stderr(serr): + res = fct() + return res, sout.getvalue(), serr.getvalue() + + +def get_parsed_args( + name: str, + scenarios: Optional[Dict[str, str]] = None, + description: Optional[str] = None, + epilog: Optional[str] = None, + number: int = 10, + repeat: int = 10, + warmup: int = 5, + sleep: float = 0.1, + tries: int = 2, + **kwargs: Dict[str, Tuple[Union[int, str, float], str]], +) -> ArgumentParser: + """ + Returns parsed arguments for examples in this package. + + :param name: script name + :param scenarios: list of available scenarios + :param description: parser description + :param epilog: text at the end of the parser + :param number: default value for number parameter + :param repeat: default value for repeat parameter + :param warmup: default value for warmup parameter + :param sleep: default value for sleep parameter + :param kwargs: additional parameters, + example: `n_trees=(10, "number of trees to train")` + :return: parser + """ + if description is None: + description = f"Available options for {name}.py." + if epilog is None: + epilog = "" + parser = ArgumentParser(prog=name, description=description, epilog=epilog) + if scenarios is not None: + rows = ", ".join(f"{k}: {v}" for k, v in scenarios.items()) + parser.add_argument("-s", "--scenario", help=f"Available scenarios: {rows}.") + parser.add_argument( + "-n", + "--number", + help="number of executions to measure", + type=int, + default=number, + ) + parser.add_argument( + "-r", + "--repeat", + help="number of times to repeat the measure", + type=int, + default=repeat, + ) + parser.add_argument( + "-w", + "--warmup", + help="number of times to repeat the measure", + type=int, + default=warmup, + ) + parser.add_argument( + "-S", + "--sleep", + help="sleeping time between two configurations", + type=float, + default=sleep, + ) + parser.add_argument( + "-t", + "--tries", + help="number of tries for each configurations", + type=int, + default=tries, + ) + for k, v in kwargs.items(): + parser.add_argument( + f"--{k}", + help=v[1], + type=type(v[0]), + default=v[0], + ) + + return parser.parse_args() diff --git a/teachpyx/faq/__init__.py b/teachpyx/faq/__init__.py new file mode 100644 index 00000000..b4f3a7ec --- /dev/null +++ b/teachpyx/faq/__init__.py @@ -0,0 +1 @@ +from .faq_python import enumerate_regex_search # noqa: F401 diff --git a/src/teachpyx/faq/faq_exception.py b/teachpyx/faq/faq_exception.py similarity index 69% rename from src/teachpyx/faq/faq_exception.py rename to teachpyx/faq/faq_exception.py index 0eadefb2..5e6b4bc0 100644 --- a/src/teachpyx/faq/faq_exception.py +++ b/teachpyx/faq/faq_exception.py @@ -13,4 +13,6 @@ def call_stack(): @return traceback """ exc_traceback = sys.exc_info()[-1] - return traceback.extract_tb(exc_traceback), "".join(traceback.format_tb(exc_traceback)) + return traceback.extract_tb(exc_traceback), "".join( + traceback.format_tb(exc_traceback) + ) diff --git a/src/teachpyx/faq/faq_numpy.py b/teachpyx/faq/faq_numpy.py similarity index 100% rename from src/teachpyx/faq/faq_numpy.py rename to teachpyx/faq/faq_numpy.py diff --git a/src/teachpyx/faq/faq_python.py b/teachpyx/faq/faq_python.py similarity index 65% rename from src/teachpyx/faq/faq_python.py rename to teachpyx/faq/faq_python.py index 6dae3037..bf5cb1a1 100644 --- a/src/teachpyx/faq/faq_python.py +++ b/teachpyx/faq/faq_python.py @@ -1,13 +1,7 @@ -# -*- coding: utf-8 -*- -# pylint: disable=C0115,C0116 -""" -@file -@brief Quelques questions d'ordre général autour du langage Python. +# coding: utf-8 -""" - -import os import io +import os import re @@ -20,8 +14,10 @@ def entier_grande_taille(): La version 3 du langage Python a supprimé la constante ``sys.maxint`` qui définissait l'entier le plus grand (voir - `What's New In Python 3.0 `_). - De ce fait la fonction `getrandbit `_ + `What's New In Python 3.0 + `_). + De ce fait la fonction + `getrandbit `_ retourne un entier aussi grand que l'on veut. :: @@ -32,22 +28,31 @@ def entier_grande_taille(): Qui affiche :: - 2882159224557107513165483098383814837021447484558010147211921304219017212673656549681269862792029... + 2882159224557107513165483098383814837021447484558010147211921 + 304219017212673656549681269862792029... - Les calculs en nombre réels se font toujours avec huit octets de précision. - Au delà, il faut utiliser la librairie `gmpy2 `_. - Il est également recommandé d'utiliser cette librairie pour les grands nombres entiers - (entre 20 et 40 chiffres). La librairie est plus rapide que l'implémentation - du langage Python (voir `Overview of gmpy2 `_). + Les calculs en nombre réels se font toujours avec + huit octets de précision. + Au delà, il faut utiliser la librairie `gmpy2 + `_. + Il est également recommandé d'utiliser cette + librairie pour les grands nombres entiers + (entre 20 et 40 chiffres). La librairie est + plus rapide que l'implémentation + du langage Python (voir `Overview of gmpy2 + `_). .. faqref:: :tag: python :title: Tabulations ou espace ? - Il est préférable de ne pas utiliser les tabulations et de les remplacer par des espaces. - Lorsqu'on passe d'un Editeur à un autre, les espaces ne bougent pas. Les tabulations sont plus ou moins grandes visuellement. + Il est préférable de ne pas utiliser les tabulations et + de les remplacer par des espaces. + Lorsqu'on passe d'un Editeur à un autre, les espaces ne bougent pas. + Les tabulations sont plus ou moins grandes visuellement. L'essentiel est de ne pas mélanger. - Dans `SciTE `_, il faut aller dans le menu Options / Change Indentation Settings... + Dans `SciTE `_, + il faut aller dans le menu Options / Change Indentation Settings... Tous les éditeurs ont une option similaire. """ pass @@ -59,9 +64,11 @@ def difference_div(): :tag: python :title: Quelle est la différence entre / et // - division ? - Le résultat de la division avec l'opérateur ``/`` est toujours réel : + Le résultat de la division avec l'opérateur ``/`` + est toujours réel : la division de deux entiers ``1/2`` donne ``0.5``. - Le résultat de la division avec l'opérateur ``//`` est toujours entier. + Le résultat de la division avec l'opérateur ``//`` + est toujours entier. Il correspond au quotient de la division. .. runpython:: @@ -81,8 +88,10 @@ def difference_div(): print( 5 % 2 ) # affiche 1 C'est uniquement vrai pour les version Python 3.x. - Pour les versions 2.x, les opérateurs ``/`` et ``//`` avaient des comportements différents - (voir `What’s New In Python 3.0 `_). + Pour les versions 2.x, les opérateurs ``/`` et ``//`` + avaient des comportements différents + (voir `What’s New In Python 3.0 + `_). """ div1 = 1 / 2 div2 = 4 / 2 @@ -94,13 +103,17 @@ def difference_div(): def python_path(): """ .. faqref:: - :tag: module - :title: Comment éviter sys.path.append... quand on développe un module ? + :tag: python + :title: Comment éviter sys.path.append... + quand on développe un module ? Lorsqu'on développe un module, - on ne veut pas l'installer. On ne veut pas qu'il soit présent dans le répertoire ``site-packages`` de la distribution - de Python car cela introduit deux versions : celle qu'on développe et celle qu'on a installer. - Avant, je faisais cela pour créer un petit programme utilisant mon propre module + on ne veut pas l'installer. On ne veut pas qu'il soit présent + dans le répertoire ``site-packages`` de la distribution + de Python car cela introduit deux versions : + celle qu'on développe et celle qu'on a installer. + Avant, je faisais cela pour créer un petit + programme utilisant mon propre module (et on en trouve quelque trace dans mon code) : :: @@ -109,11 +122,14 @@ def python_path(): sys.path.append("c:/moncode/monmodule/src") import monmodule - Quand je récupère un programme utilisant ce module, il me faudrait ajouter + Quand je récupère un programme utilisant ce module, + il me faudrait ajouter ces petites lignes à chaque fois et c'est barbant. - Pour éviter cela, il est possible de dire à l'interpréteur Python d'aller chercher + Pour éviter cela, il est possible de dire à + l'interpréteur Python d'aller chercher ailleurs pour trouver des modules en ajoutant le chemin à la - `variable d'environnement `_ + `variable d'environnement + `_ `PYTHONPATH `_. Sous Windows : @@ -127,7 +143,8 @@ def python_path(): def same_variable(a, b): """ Cette fonction dit si les deux objets sont en fait le même objet (True) - ou non (False) s'ils sont différents (même s'ils contiennent la même information). + ou non (False) s'ils sont différents + (même s'ils contiennent la même information). :param a: n'importe quel objet :param b: n'importe quel objet @@ -138,16 +155,21 @@ def same_variable(a, b): :title: Qu'est-ce qu'un type immuable ou immutable ? :lid: faq-py-immutable - Une variable de type *immuable* ne peut être modifiée. Cela concerne principalement : + Une variable de type *immuable* ne peut être modifiée. + Cela concerne principalement : - ``int``, ``float``, ``str``, ``tuple`` - Si une variable est de type *immuable*, lorsqu'on effectue une opération, + Si une variable est de type *immuable*, + lorsqu'on effectue une opération, on créé implicitement une copie de l'objet. - Les dictionnaires et les listes sont *modifiables* (ou *mutable*). Pour une variable - de ce type, lorsqu'on écrit ``a = b``, ``a`` et ``b`` désigne le même objet même - si ce sont deux noms différentes. C'est le même emplacement mémoire + Les dictionnaires et les listes sont + *modifiables* (ou *mutable*). Pour une variable + de ce type, lorsqu'on écrit ``a = b``, ``a`` et ``b`` + désigne le même objet même + si ce sont deux noms différentes. + C'est le même emplacement mémoire accessible paur deux moyens (deux identifiants). Par exemple :: @@ -164,10 +186,14 @@ def same_variable(a, b): print( a == b ) # --> True print(a,b) # --> [2, 3, 4, 5] [2, 3, 4, 5] - Dans le premier cas, le type (``tuple``) est _immutable_, l'opérateur ``+=`` cache implicitement une copie. - Dans le second cas, le type (``list``) est _mutable_, l'opérateur ``+=`` évite la copie - car la variable peut être modifiée. Même si ``b=a`` est exécutée avant l'instruction suivante, - elle n'a **pas** pour effet de conserver l'état de ``a`` avant l'ajout d'élément. + Dans le premier cas, le type (``tuple``) est _immutable_, + l'opérateur ``+=`` cache implicitement une copie. + Dans le second cas, le type (``list``) est _mutable_, + l'opérateur ``+=`` évite la copie + car la variable peut être modifiée. Même si ``b=a`` + est exécutée avant l'instruction suivante, + elle n'a **pas** pour effet de conserver l'état de ``a`` avant + l'ajout d'élément. Un autre exemple :: a = [1, 2] @@ -184,8 +210,10 @@ def same_variable(a, b): print(a) # --> [-1, 2] print(b) # --> [1, 2] - La page `Immutable Sequence Types `_ - détaille un peu plus le type qui sont *mutable* et ceux qui sont *immutable*. Parmi les types standards : + La page `Immutable Sequence Types + `_ + détaille un peu plus le type qui sont *mutable* et ceux qui + sont *immutable*. Parmi les types standards : * **mutable** * `bool `_ @@ -209,21 +237,31 @@ def same_variable(a, b): * `__slots__ `_ * `How to Create Immutable Classes in Python `_ - * `Ways to make a class immutable in Python `_ - * `freeze `_ - - Enfin, pour les objects qui s'imbriquent les uns dans les autres, une liste de listes, une classe - qui incluent des dictionnaires et des listes, on distingue une copie simple d'une copie intégrale (**deepcopy**). - Dans le cas d'une liste de listes, la copie simple recopie uniquement la première liste :: + * `Ways to make a class immutable in Python + `_ + * surcharger des méthodes `__getattr__ + `_, + `__getattribute__ + `_, + `__setattr__ + `_. + + + Enfin, pour les objects qui s'imbriquent les uns dans + les autres, une liste de listes, une classe + qui incluent des dictionnaires et des listes, + on distingue une copie simple d'une copie intégrale (**deepcopy**). + Dans le cas d'une liste de listes, la copie simple + recopie uniquement la première liste :: import copy l1 = [ [0,1], [2,3] ] l2 = copy.copy(l1) l1 [0][0] = '##' - print(l1,l2) # --> [['##', 1], [2, 3]] [['##', 1], [2, 3]] + print(l1, l2) # --> [['##', 1], [2, 3]] [['##', 1], [2, 3]] l1 [0] = [10,10] - print(l1,l2) # --> [[10, 10], [2, 3]] [['##', 1], [2, 3]] + print(l1,l2) # --> [[10, 10], [2, 3]] [['##', 1], [2, 3]] La copie intégrale recopie également les objets inclus :: @@ -231,9 +269,10 @@ def same_variable(a, b): l1 = [ [0,1], [2,3] ] l2 = copy.deepcopy(l1) l1 [0][0] = '##' - print(l1,l2) # --> [['##', 1], [2, 3]] [[0, 1], [2, 3]] + print(l1,l2) # --> [['##', 1], [2, 3]] [[0, 1], [2, 3]] - Les deux fonctions s'appliquent à tout object Python : `module copy `_. + Les deux fonctions s'appliquent à tout object Python : + `module copy `_. """ return id(a) == id(b) @@ -249,9 +288,12 @@ def stringio(text): :tag: python :title: A quoi sert un ``StringIO`` ? - La plupart du temps, lorsqu'on récupère des données, elles sont sur le disque dur - de votre ordinateur dans un fichier texte. Lorsqu'on souhaite automatiser un processur - qu'on répète souvent avec ce fichier, on écrit une fonction qui prend le nom du fichier en entrée. + La plupart du temps, lorsqu'on récupère des données, + elles sont sur le disque dur + de votre ordinateur dans un fichier texte. Lorsqu'on + souhaite automatiser un processur + qu'on répète souvent avec ce fichier, on écrit une + fonction qui prend le nom du fichier en entrée. :: @@ -263,18 +305,27 @@ def processus_quotidien(nom_fichier) : nb += 1 return nb - Et puis un jour, les données ne sont plus dans un fichier mais sur Internet. - Le plus simple dans ce cas est de recopier ces données sur disque dur et d'appeler la même fonction. - Simple. Un autre les données qu'on doit télécharger font plusieurs gigaoctets. Tout télécharger prend - du temps pour finir pour s'apercevoir qu'elles sont corrompues. On a perdu plusieurs heures pour rien. - On aurait bien voulu que la fonction ``processus_quotidien`` commence à traiter les données + Et puis un jour, les données ne sont plus dans un fichier + mais sur Internet. + Le plus simple dans ce cas est de recopier ces données sur disque + dur et d'appeler la même fonction. + Simple. Un autre les données qu'on doit télécharger font plusieurs + gigaoctets. Tout télécharger prend + du temps pour finir pour s'apercevoir qu'elles sont corrompues. + On a perdu plusieurs heures pour rien. + On aurait bien voulu que la fonction ``processus_quotidien`` + commence à traiter les données dès le début du téléchargement. - Pour cela, on a inventé la notion de **stream** ou **flux** qui sert d'interface entre la fonction - qui traite les données et la source des données. Le flux lire les données depuis n'importe quel source - (fichier, internet, mémoire), la fonction qui les traite n'a pas besoin d'en connaître la provenance. + Pour cela, on a inventé la notion de **stream** ou **flux** + qui sert d'interface entre la fonction + qui traite les données et la source des données. + Le flux lire les données depuis n'importe quel source + (fichier, internet, mémoire), la fonction qui les traite + n'a pas besoin d'en connaître la provenance. - `StringIO `_ est un flux qui considère + `StringIO `_ + est un flux qui considère la mémoire comme source de données. :: @@ -286,7 +337,8 @@ def processus_quotidien(data_stream): nb += 1 return nb - La fonction ``processus_quotidien`` fonctionne pour des données en mémoire + La fonction ``processus_quotidien`` + fonctionne pour des données en mémoire et sur un fichier. :: @@ -308,10 +360,11 @@ def property_example(): """ .. faqref:: - :tag: class + :tag: python :title: property - Une `property `_ est + Une `property + `_ est une écriture qui sert à transformer l'appel d'une méthode de classe en un attribut. @@ -338,8 +391,10 @@ def norm2(self): print(c.x) print(c.y) - ``x`` est définit comme une méthode mais elle retourne simplement l'attribut - ``_x``. De cette façon, il est impossible de changer ``x`` en écrivant:: + ``x`` est définit comme une méthode mais elle + retourne simplement l'attribut + ``_x``. De cette façon, il est impossible de + changer ``x`` en écrivant:: c.x = 5 @@ -358,17 +413,19 @@ def norm2(self): def enumerate_regex_search(exp, text): """ - Cette fonction itère sur les différentes occurences d'une expression régulière. + Cette fonction itère sur les différentes occurences + d'une expression régulière. :param exp: expression régulière :param text: text à parser :return: itérateur .. faqref:: - :tag: regex + :tag: python :title: Comment itérer sur les résultats d'une expression régulière ? - On utilise la méthode `finditer `_. + On utilise la méthode + `finditer `_. :: @@ -376,7 +433,8 @@ def enumerate_regex_search(exp, text): for m in exp.finditer(text): # ... - Voir également `Petites subtilités avec les expressions régulières en Python + Voir également `Petites subtilités avec les expressions + régulières en Python `_. """ # found = exp.search(text) @@ -389,10 +447,11 @@ def enumerate_regex_search(exp, text): def sortable_class(cl): """ .. faqref:: - :tag: class + :tag: python :title: Classe sortable - Il faut prononcer *sortable* à l'anglaise. Comment rendre une classe + Il faut prononcer *sortable* à l'anglaise. + Comment rendre une classe *sortable* ? Pour faire simple, on veut écrire :: l = [ o1, o2 ] @@ -430,11 +489,13 @@ def list_of_installed_packages(): calls ``pip list`` to retrieve the list of packages .. faqref:: - :tag: module + :tag: python :title: Obtenir des informations sur les packages installés - Le module `pip `_ retourne des informations - sur n'importe quel module installé, sa version, sa license :: + Le module `pip `_ + retourne des informations + sur n'importe quel module installé, sa version, + sa license :: pip show pandas @@ -447,7 +508,8 @@ def list_of_installed_packages(): Name: pandas Version: 0.16.0 - Summary: Powerful data structures for data analysis, time series,and statistics + Summary: Powerful data structures for data analysis, + time series,and statistics Home-page: http://pandas.pydata.org Author: The PyData Development Team Author-email: pydata@googlegroups.com @@ -456,7 +518,8 @@ def list_of_installed_packages(): Requires: python-dateutil, pytz, numpy On utilise également ``pip freeze`` pour répliquer l'environnement - dans lequel on a développé un programme. `pip freeze `_ + dans lequel on a développé un programme. + `pip freeze `_ produit la liste des modules avec la version utilisée :: docutils==0.11 @@ -465,29 +528,38 @@ def list_of_installed_packages(): Pygments==1.6 Sphinx==1.2.2 - Ce qu'on utilise pour répliquer l'environnement de la manière suivante :: + Ce qu'on utilise pour répliquer l'environnement + de la manière suivante :: pip freeze > requirements.txt pip install -r requirements.txt - Cette façon de faire fonctionne très bien sous Linux mais n'est pas encore - opérationnelle sous Windows à moins d'installer le compilateur C++ utilisée pour compiler + Cette façon de faire fonctionne très bien sous + Linux mais n'est pas encore + opérationnelle sous Windows à moins d'installer + le compilateur + C++ utilisée pour compiler Python. """ - from pyquickhelper.pycode.pip_helper import get_packages_list # pylint: disable=C0415 + from pyquickhelper.pycode.pip_helper import ( + get_packages_list, + ) # pylint: disable=C0415 + return get_packages_list() def information_about_package(name): """ - calls ``pip show`` to retrieve information about packages + Calls ``pip show`` to retrieve information about packages. .. faqref:: - :tag: module + :tag: python :title: Récupérer la liste des modules installés - Le module `pip `_ permet d'installer - de nouveaux modules mais aussi d'obtenir la liste des packages installés :: + Le module `pip `_ + permet d'installer + de nouveaux modules mais aussi d'obtenir la liste + des packages installés :: pip list @@ -498,9 +570,11 @@ def information_about_package(name): .. faqref:: :tag: python - :title: Pourquoi l'installation de pandas (ou numpy) ne marche pas sous Windows avec pip ? + :title: Pourquoi l'installation de pandas (ou numpy) + ne marche pas sous Windows avec pip ? - Python est un langage très lent et c'est pourquoi la plupart des modules de calculs numériques + Python est un langage très lent et c'est pourquoi la + plupart des modules de calculs numériques incluent des parties implémentées en langage C++. `numpy `_, `pandas `_, @@ -509,29 +583,29 @@ def information_about_package(name): `scikit-learn `_, ... - Sous Linux, le compilateur est intégré au système et l'installation de ces modules via - l'instruction ``pip install `` met implicitement le compilateur à contribution. - Sous Windows, il n'existe pas de compilateur C++ par défaut à moins de l'installer. + Sous Linux, le compilateur est intégré au système et + l'installation de ces modules via + l'instruction ``pip install `` met implicitement + le compilateur à contribution. + Sous Windows, il n'existe pas de compilateur C++ par + défaut à moins de l'installer. Il faut faire attention alors d'utiliser exactement le même que celui utilisé pour compiler Python (voir `Compiling Python on Windows `_). C'est pour cela qu'on préfère utiliser des distributions comme - `Anaconda `_ + `Anaconda `_ qui propose par défaut - une version de Python accompagnée des modules les plus utilisés. Elle propose également une façon + une version de Python accompagnée des modules les plus utilisés. + Elle propose également une façon simple d'installer des modules précompilés avec l'instruction :: conda install - - L'autre option est d'utilser le site - `Unofficial Windows Binaries for Python Extension Packages `_ - qui propose des versions compilées sous Windows d'un grand nombre de modules. - Il faut télécharger le fichier *.whl* puis l'installer avec l'instruction ``pip install ``. - La différence entre les deux ooptions tient aux environnements virtuels, voir - `Python virtual environments `_. """ - from pyquickhelper.pycode.pip_helper import get_package_info # pylint: disable=C0415 + from pyquickhelper.pycode.pip_helper import ( + get_package_info, + ) # pylint: disable=C0415 + return get_package_info(name)