├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── codeql │ └── codeql-config.yml └── workflows │ ├── build.yml │ ├── codeql.yml │ └── test.yml ├── .gitignore ├── .readthedocs.yml ├── AUTHORS.rst ├── CHANGES.rst ├── CODE_OF_CONDUCT.rst ├── CONTRIBUTING.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── ROADMAP.rst ├── conf ├── 90-usb-microbit.rules ├── mu.appdata.xml ├── mu.codewith.editor.desktop └── mu.codewith.editor.png ├── debian ├── changelog ├── compat ├── control ├── copyright ├── mu.install ├── py3dist-overrides ├── rules └── source │ ├── format │ └── options ├── docs ├── Makefile ├── api.rst ├── architecture.rst ├── authors.rst ├── awesome.gif ├── beautifully_useless.jpg ├── changes.rst ├── circuit_playground.jpg ├── code_of_conduct.rst ├── conf.py ├── contributing.rst ├── copyright.rst ├── debugger-notes.log ├── debugger.rst ├── design.rst ├── design │ ├── file_reading_and_writing.rst │ ├── line-endings.rst │ ├── runtime_virtual_environment.rst │ ├── settings-and-sessions.rst │ └── template-decision.txt ├── first-steps.rst ├── icon.png ├── icon_brief │ ├── README.txt │ ├── debug-icons.png │ ├── mu-adafruit.png │ ├── mu-annotated_ui.png │ ├── mu-high-contrast.png │ ├── mu-microbit.png │ ├── mu-mode-select.png │ ├── mu-python.png │ └── mu-running.png ├── icon_small.png ├── index.rst ├── jupyter-notes.log ├── license.rst ├── logo.png ├── logo_design │ ├── balloon.svg │ ├── logo.png │ ├── mu-logo-large.png │ ├── mu-logo-large.xcf │ ├── mu-logo-nocap.svg │ ├── mu-logo.png │ ├── mu-logo.svg │ ├── pythonic_world.jpg │ ├── red_python.png │ ├── splash-screen.png │ ├── splash.xcf │ ├── world.jpg │ └── world.png ├── make.bat ├── microbit.png ├── modes.rst ├── mu-debugger.png ├── mu-startup-notes.log ├── mu_sketch.jpg ├── packaging.rst ├── pygame.png ├── python.png ├── release.rst ├── roadmap.rst ├── setup.rst ├── swag │ └── t-shirts │ │ ├── Baby.png │ │ ├── Baby.svg │ │ ├── Carlos.png │ │ ├── Carlos.svg │ │ ├── Daniel Pope.png │ │ ├── Daniel Pope.svg │ │ ├── Lady Ada.png │ │ ├── Lady Ada.svg │ │ ├── Phil.png │ │ ├── Stig.png │ │ ├── Stig.svg │ │ ├── Tim Golden.png │ │ ├── Tim Golden.svg │ │ ├── arrr.svg │ │ ├── arrr.svg.png │ │ ├── dnek.svg │ │ ├── philbin.png │ │ └── philbin.svg ├── tests.rst ├── translations.rst ├── user-experience.rst └── website.rst ├── make.cmd ├── make.py ├── mu ├── __init__.py ├── __main__.py ├── app.py ├── config.py ├── contrib │ ├── __init__.py │ ├── esptool.py │ ├── microfs.py │ └── uflash.py ├── debugger │ ├── client.py │ ├── config.py │ ├── runner.py │ └── utils.py ├── i18n.py ├── interface │ ├── __init__.py │ ├── dialogs.py │ ├── editor.py │ ├── main.py │ ├── panes.py │ ├── themes.py │ ├── widgets.py │ └── workers.py ├── locale │ ├── de_DE │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── es │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── fr │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── ja │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── nl │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── pl │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── pt_BR │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── pt_PT │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── ru_RU │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── sk_SK │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── sv │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── uk_UA │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ ├── vi │ │ └── LC_MESSAGES │ │ │ ├── mu.mo │ │ │ └── mu.po │ └── zh_CN │ │ └── LC_MESSAGES │ │ ├── mu.mo │ │ └── mu.po ├── logic.py ├── modes │ ├── __init__.py │ ├── api │ │ ├── __init__.py │ │ ├── adafruit.py │ │ ├── esp.py │ │ ├── flask.py │ │ ├── lego.py │ │ ├── microbit.py │ │ ├── pi.py │ │ ├── pyboard.py │ │ ├── pygamezero.py │ │ ├── python3.py │ │ ├── shared.py │ │ └── snek.py │ ├── base.py │ ├── circuitpython.py │ ├── debugger.py │ ├── esp.py │ ├── lego.py │ ├── microbit.py │ ├── pico.py │ ├── pyboard.py │ ├── pygamezero.py │ ├── python3.py │ ├── snek.py │ └── web.py ├── mu_debug.py ├── resources │ ├── __init__.py │ ├── css │ │ ├── contrast.css │ │ ├── day.css │ │ └── night.css │ ├── fonts │ │ ├── LICENSE.txt │ │ ├── SourceCodePro-Bold.otf │ │ ├── SourceCodePro-BoldIt.otf │ │ ├── SourceCodePro-It.otf │ │ ├── SourceCodePro-Regular.otf │ │ ├── SourceCodePro-Semibold.otf │ │ └── SourceCodePro-SemiboldIt.otf │ ├── images │ │ ├── PA-logo-snake-only.svg │ │ ├── browse.png │ │ ├── browse.svg │ │ ├── button.png │ │ ├── button.svg │ │ ├── check-bad.png │ │ ├── check-bad.svg │ │ ├── check-good.png │ │ ├── check-good.svg │ │ ├── check.png │ │ ├── check.svg │ │ ├── checked.png │ │ ├── checked.svg │ │ ├── chip-connected.svg │ │ ├── chip-disconnected.svg │ │ ├── circuitpython.png │ │ ├── circuitpython.svg │ │ ├── close-tab.svg │ │ ├── css.png │ │ ├── css.svg │ │ ├── debug.png │ │ ├── debug.svg │ │ ├── deploy.png │ │ ├── deploy.svg │ │ ├── document-dirty.svg │ │ ├── document.svg │ │ ├── dropdown-arrow-contrast.png │ │ ├── dropdown-arrow-contrast.svg │ │ ├── dropdown-arrow-night.png │ │ ├── dropdown-arrow-night.svg │ │ ├── dropdown-arrow.png │ │ ├── dropdown-arrow.svg │ │ ├── esp.png │ │ ├── files.png │ │ ├── files.svg │ │ ├── flash.png │ │ ├── flash.svg │ │ ├── fonts.png │ │ ├── fonts.svg │ │ ├── getflash.svg │ │ ├── help.png │ │ ├── help.svg │ │ ├── icon.png │ │ ├── icon.svg │ │ ├── images.png │ │ ├── images.svg │ │ ├── language.svg │ │ ├── lego.png │ │ ├── load.png │ │ ├── load.svg │ │ ├── logs.png │ │ ├── logs.svg │ │ ├── microbit.png │ │ ├── modes.png │ │ ├── modes.svg │ │ ├── music.png │ │ ├── music.svg │ │ ├── new.png │ │ ├── new.svg │ │ ├── pico.png │ │ ├── play.png │ │ ├── play.svg │ │ ├── plotter.png │ │ ├── plotter.svg │ │ ├── pyboard.png │ │ ├── pygamezero.png │ │ ├── python.png │ │ ├── python.svg │ │ ├── quit.png │ │ ├── quit.svg │ │ ├── repl.png │ │ ├── repl.svg │ │ ├── run.png │ │ ├── run.svg │ │ ├── save.png │ │ ├── save.svg │ │ ├── scroll-down.png │ │ ├── scroll-down.svg │ │ ├── scroll-left.png │ │ ├── scroll-left.svg │ │ ├── scroll-right.png │ │ ├── scroll-right.svg │ │ ├── scroll-up.png │ │ ├── scroll-up.svg │ │ ├── serial.png │ │ ├── serial.svg │ │ ├── snek.svg │ │ ├── snippets.png │ │ ├── snippets.svg │ │ ├── sounds.png │ │ ├── sounds.svg │ │ ├── splash-screen.png │ │ ├── splash_fail.png │ │ ├── splash_screen.gif │ │ ├── splash_screen.xcf │ │ ├── splash_screen_base_image.png │ │ ├── static.png │ │ ├── static.svg │ │ ├── step-in.png │ │ ├── step-in.svg │ │ ├── step-out.png │ │ ├── step-out.svg │ │ ├── step-over.png │ │ ├── step-over.svg │ │ ├── stop.png │ │ ├── stop.svg │ │ ├── templates.png │ │ ├── templates.svg │ │ ├── theme.png │ │ ├── theme.svg │ │ ├── theme_contrast.png │ │ ├── theme_contrast.svg │ │ ├── theme_day.png │ │ ├── theme_day.svg │ │ ├── tidy.png │ │ ├── tidy.svg │ │ ├── web.png │ │ ├── zoom-in.png │ │ ├── zoom-in.svg │ │ ├── zoom-out.png │ │ └── zoom-out.svg │ ├── pygamezero │ │ ├── alien.png │ │ ├── alien_hurt.png │ │ ├── cat1.png │ │ ├── cat2.png │ │ ├── cat3.png │ │ ├── cat4.png │ │ ├── eep.wav │ │ ├── meow1.wav │ │ ├── meow2.wav │ │ ├── meow3.wav │ │ ├── meow4.wav │ │ ├── splat.png │ │ └── splat.wav │ └── web │ │ ├── static │ │ ├── css │ │ │ ├── normalize.css │ │ │ └── skeleton.css │ │ └── img │ │ │ └── logo.png │ │ └── templates │ │ ├── age.html │ │ ├── base.html │ │ ├── greeting.html │ │ └── index.html ├── settings.py ├── virtual_environment.py └── wheels │ ├── __init__.py │ └── __main__.py ├── package ├── README.rst ├── __init__.py ├── dmg_settings.py ├── icons │ ├── mac_icon.icns │ └── win_icon.ico ├── install_pip3.sh └── qt.conf ├── requirements.txt ├── run.py ├── setup.cfg ├── setup.py ├── tests ├── README.rst ├── __init__.py ├── conftest.py ├── customhextest.hex ├── debugger │ ├── __init__.py │ ├── test_client.py │ ├── test_runner.py │ └── test_utils.py ├── interface │ ├── __init__.py │ ├── test_dialogs.py │ ├── test_editor.py │ ├── test_main.py │ ├── test_panes.py │ ├── test_themes.py │ ├── test_widgets.py │ └── test_workers.py ├── modes │ ├── __init__.py │ ├── chromeos_devpath_exists.txt │ ├── chromeos_devpath_missing.txt │ ├── mount_exists.txt │ ├── mount_missing.txt │ ├── test_base.py │ ├── test_circuitpython.py │ ├── test_debug.py │ ├── test_esp.py │ ├── test_lego.py │ ├── test_microbit.py │ ├── test_pico.py │ ├── test_pyboard.py │ ├── test_pygamezero.py │ ├── test_python3.py │ ├── test_snek.py │ └── test_web.py ├── scripts │ ├── .gitignore │ ├── contains_blue.py │ ├── contains_brown.py │ ├── contains_green.py │ ├── contains_red.py │ └── pycodestyle ├── session.json ├── settings.json ├── settingscorrupt.json ├── settingswithcustomhex.json ├── settingswithmissingcustomhex.json ├── settingswithoutworkspace.json ├── test_app.py ├── test_logic.py ├── test_resources.py ├── test_settings.py └── virtual_environment │ ├── test_pip.py │ ├── test_process.py │ ├── test_virtual_environment.py │ └── wheels │ ├── arrr-1.0.2-py3-none-any.whl │ └── wheels.zip └── utils ├── README.rst ├── adafruit.json ├── adafruit_api.py ├── avatar.py ├── flask.json ├── flask_api.py ├── gh_downloads.py ├── mkapi.py ├── pgzero_api.json ├── pgzero_api.py ├── python3_api.py └── python_api.json /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a problem with the Mu editor. 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Thanks for taking the time to fill out this bug report! 8 | 9 | Please answer each question below to the best of your ability. 10 | It's okay to leave some blank if it doesn't apply to your problem. 11 | - type: input 12 | attributes: 13 | label: What were you trying to do? 14 | validations: 15 | required: false 16 | - type: textarea 17 | attributes: 18 | label: What steps did you take to trigger the issue? 19 | validations: 20 | required: false 21 | - type: input 22 | attributes: 23 | label: What did you expect to happen? 24 | validations: 25 | required: false 26 | - type: textarea 27 | attributes: 28 | label: What actually happened? 29 | validations: 30 | required: false 31 | - type: input 32 | attributes: 33 | label: Operating System Version 34 | validations: 35 | required: false 36 | - type: input 37 | attributes: 38 | label: Mu Version 39 | validations: 40 | required: false 41 | - type: textarea 42 | attributes: 43 | label: Other Info 44 | description: You can put any info here that you think might help us track down the bug. 45 | validations: 46 | required: false 47 | - type: textarea 48 | attributes: 49 | label: Editor Log 50 | description: | 51 | Please remember to attach a **copy of the full log files for Mu**. You 52 | can get the logs by clicking on the cog icon in the bottom right of the 53 | editor window. 54 | Click on the logs and use CTRL-A to select all, then CTRL-C to copy and 55 | CTRL-V to paste the contents into the issue. 56 | If Mu doesn't open, you can find the logs in one of these locations, 57 | depending on your OS: 58 | * Windows: `%LOCALAPPDATA%\python\mu\Logs` 59 | * macOS: `~/Library/Logs/mu` 60 | * Linux: `~/.cache/mu/` 61 | validations: 62 | required: false 63 | - type: markdown 64 | attributes: 65 | value: Thank you for contributing to Mu! :-) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Request New Features 4 | url: https://github.com/mu-editor/mu/discussions/categories/ideas-new-features 5 | about: New features are first discussed here. 6 | - name: General discussion 7 | url: https://github.com/mu-editor/mu/discussions/ 8 | about: You can talk about anything else in the Discussions section. 9 | - name: Tutorials & Guides 10 | url: https://codewith.mu 11 | about: Have you checked the Mu website for documentation first? 12 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "Mu CodeQL configuration" 2 | 3 | paths-ignore: 4 | - mu/contrib/esptool.py 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Mu 2 | 3 | on: 4 | push: 5 | branches: 'master' 6 | pull_request: 7 | branches: '*' 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | os: [macos-13, windows-2019] 14 | fail-fast: false 15 | runs-on: ${{ matrix.os }} 16 | name: Build ${{ matrix.os }} 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Set up Python 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: '3.8' 23 | - name: Display Python info 24 | run: | 25 | python -c "import sys; print(sys.version)" 26 | python -c "import platform, struct; print(platform.machine(), struct.calcsize('P') * 8)" 27 | python -c "import sys; print(sys.executable)" 28 | python -m pip --version 29 | pip --version 30 | pip config list 31 | pip freeze 32 | - name: Install Mu test dependencies 33 | run: | 34 | pip install .[tests] 35 | pip list 36 | - run: mkdir upload 37 | - name: Build Windows 64 bit 38 | if: runner.os == 'Windows' 39 | run: | 40 | python make.py win64 41 | dir dist/*.msi | rename-item -newname { $_.name -replace ".msi"," (64 bit).msi" } 42 | mv dist/*.msi upload/ 43 | - name: Build macOS 44 | if: runner.os == 'macOS' 45 | run: | 46 | make macos 47 | mv dist/*.dmg upload/ 48 | - name: Upload Mu installer 49 | uses: actions/upload-artifact@v4 50 | with: 51 | name: mu-editor-${{ runner.os }}-${{ github.sha }} 52 | path: upload 53 | 54 | build-linux: 55 | runs-on: ubuntu-20.04 56 | container: 57 | image: ghcr.io/mu-editor/mu-appimage:2024.12.02 58 | name: Build AppImage 59 | steps: 60 | - uses: actions/checkout@v4 61 | - name: Display system info 62 | run: | 63 | uname -a 64 | cat /etc/os-release 65 | ldd --version 66 | python -c "import sys; print(sys.version)" 67 | python -c "import platform, struct; print(platform.machine(), struct.calcsize('P') * 8)" 68 | python -c "import sys; print(sys.executable)" 69 | python -m pip --version 70 | pip --version 71 | pip list --verbose 72 | - name: Install Mu test dependencies 73 | run: | 74 | pip install .[tests] 75 | pip list 76 | - name: Build Linux AppImage 77 | run: QT_QPA_PLATFORM=offscreen make linux 78 | # GitHub actions upload artifact breaks permissions, workaround using tar 79 | # https://github.com/actions/upload-artifact/issues/38 80 | - name: Tar AppImage to maintain permissions 81 | run: | 82 | cd dist/ 83 | tar -cvf Mu_Editor-AppImage-x86_64-${{ github.sha }}.tar *.AppImage 84 | ls -la . 85 | - name: Upload Mu AppImage 86 | uses: actions/upload-artifact@v4 87 | with: 88 | name: mu-editor-${{ runner.os }}-${{ github.sha }} 89 | path: dist/Mu_Editor-AppImage-x86_64-${{ github.sha }}.tar 90 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: '*' 6 | pull_request: 7 | branches: '*' 8 | paths-ignore: 9 | - '**/*.md' 10 | - '**/*.rst' 11 | schedule: 12 | - cron: "3 2 * * 2" 13 | 14 | jobs: 15 | analyze: 16 | timeout-minutes: 20 17 | name: Analyze 18 | runs-on: ubuntu-20.04 19 | permissions: 20 | actions: read 21 | contents: read 22 | security-events: write 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Install dependencies to help the code scanner 29 | run: pip install .[dev] 30 | 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v3 33 | with: 34 | languages: python 35 | config-file: ./.github/codeql/codeql-config.yml 36 | queries: +security-and-quality 37 | # Manually install deps, as CodeQL tries to install the empty requirements.txt 38 | setup-python-dependencies: false 39 | 40 | - name: Perform CodeQL Analysis 41 | uses: github/codeql-action/analyze@v2 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | .env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # Bluemix vendored packages 29 | vendor/ 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | #*.spec 36 | pyinstaller/ 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *,cover 51 | .pytest_cache/* 52 | 53 | # Translations 54 | *.pot 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # Emacs 60 | *~ 61 | TAGS 62 | 63 | # PyBuilder 64 | target/ 65 | 66 | # WingIDE (we do want .wpr but not .wpu) 67 | *.wpu 68 | 69 | # Vim 70 | *.swp 71 | 72 | # Pycharm 73 | .idea/ 74 | 75 | # Visual Studio Code 76 | .vscode 77 | 78 | # OSX 79 | .DS_Store 80 | /.vs/slnx.sqlite 81 | 82 | # Movie 83 | *.mp4 84 | 85 | # Virtual Environment 86 | .venv*/ 87 | /mu/wheels/*.whl 88 | /baseline_packages.json 89 | venv-pup/ 90 | /local-scripts 91 | /mu/wheels/*.zip 92 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Build documentation in the docs/ directory with Sphinx 8 | sphinx: 9 | builder: html 10 | configuration: docs/conf.py 11 | 12 | # Build the docs in additional formats such as PDF and ePub 13 | formats: all 14 | 15 | # Set the version of Python and extra requirements required to build the docs 16 | python: 17 | version: 3.6 18 | install: 19 | - method: pip 20 | path: . 21 | extra_requirements: 22 | - docs 23 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Mu's Developers 2 | =============== 3 | 4 | Mu was created and `mostly written by `_ 5 | Nicholas H.Tollervey (ntoll@ntoll.org). Some of Nicholas's work has been 6 | `magnificently supported `_ by the 7 | `Raspberry Pi Foundation `_. 8 | 9 | Happily, many people have volunteered wonderful and varied contributions to Mu. 10 | These include (but are not limited to): 11 | 12 | * Tim Golden 13 | * Peter Inglesby 14 | * Carlos Pereira Atencio 15 | * Nick Sarbicki 16 | * Kushal Das 17 | * Tibs / Tony Ibbs 18 | * Zander Brown 19 | * Alistair Broomhead 20 | * Frank Morton 21 | * Keith Packard 22 | 23 | If you have discovered a bug, please see the 24 | `tutorial on how to report a bug `_ 25 | in Mu. For other topics or help, please visit 26 | `GitHub Discussions `_. 27 | 28 | We welcome contributions from anyone! Please see :doc:`contributing` for more 29 | information. 30 | 31 | If you have made a contribution to Mu and would like to be recognised, please 32 | feel to add yourself to the list above. 33 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.rst: -------------------------------------------------------------------------------- 1 | Code of Conduct 2 | --------------- 3 | 4 | We expect contributors to follow the 5 | `Python Software Foundation's Code of Conduct `_, 6 | reproduced below. 7 | 8 | The Python community is made up of members from around the globe with a diverse 9 | set of skills, personalities, and experiences. It is through these differences 10 | that our community experiences great successes and continued growth. When 11 | you're working with members of the community, we encourage you to follow these 12 | guidelines which help steer our interactions and strive to keep Python a 13 | positive, successful, and growing community. 14 | 15 | A member of the Python community is: 16 | 17 | Open 18 | ++++ 19 | 20 | Members of the community are open to collaboration, whether it's on PEPs, 21 | patches, problems, or otherwise. We're receptive to constructive comment and 22 | criticism, as the experiences and skill sets of other members contribute to the 23 | whole of our efforts. We're accepting of all who wish to take part in our 24 | activities, fostering an environment where anyone can participate and everyone 25 | can make a difference. 26 | 27 | Considerate 28 | +++++++++++ 29 | 30 | Members of the community are considerate of their peers -- other Python users. 31 | We're thoughtful when addressing the efforts of others, keeping in mind that 32 | often times the labor was completed simply for the good of the community. We're 33 | attentive in our communications, whether in person or online, and we're tactful 34 | when approaching differing views. 35 | 36 | Respectful 37 | ++++++++++ 38 | 39 | Members of the community are respectful. We're respectful of others, their 40 | positions, their skills, their commitments, and their efforts. We're respectful 41 | of the volunteer efforts that permeate the Python community. We're respectful 42 | of the processes set forth in the community, and we work within them. When we 43 | disagree, we are courteous in raising our issues. 44 | 45 | Overall, we're good to each other. We contribute to this community not because 46 | we have to, but because we want to. If we remember that, these guidelines will 47 | come naturally. 48 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing to Mu 2 | ------------------ 3 | 4 | Hey! Many thanks for wanting to improve Mu. 5 | 6 | Contributions are welcome without prejudice from *anyone* irrespective of 7 | age, gender, religion, race or sexuality. If you're thinking, "but they don't 8 | mean me", *then we especially mean YOU*. Good quality code and engagement 9 | with respect, humour and intelligence wins every time. 10 | 11 | * If you're from a background which isn't well-represented in most geeky 12 | groups, get involved - *we want to help you make a difference*. 13 | * If you're from a background which *is* well-represented in most geeky 14 | groups, get involved - *we want your help making a difference*. 15 | * If you're worried about not being technical enough, get involved - *your 16 | fresh perspective will be invaluable*. 17 | * If you think you're an imposter, get involved. 18 | * If your day job isn't code, get involved. 19 | * This isn't a group of experts, just people. Get involved! 20 | * We are interested in educational, social and technical problems. If you are 21 | too, get involved. 22 | * This is a new community. *No-one knows what they are doing*, so, get involved. 23 | 24 | We expect contributors to follow our `code_of_conduct `_. 25 | 26 | Check out our 27 | `developer setup `_ 28 | documentation for instructions to configure a working development environment 29 | for Mu. 30 | 31 | Feedback may be given for contributions and, where necessary, changes will 32 | be politely requested and discussed with the originating author. Respectful 33 | yet robust argument is most welcome. 34 | 35 | .. warning:: 36 | 37 | **Contributions are subject to the following caveats**: the contribution 38 | was created by the contributor who, by submitting the contribution, is 39 | confirming that they have the authority to submit the contribution and 40 | place it under the license as defined in the LICENSE file found within 41 | this repository (see :doc:`license`). If this is a significant contribution 42 | the contributor should add themselves to the AUTHORS file found in the 43 | root of Mu's repository, otherwise they agree, for the sake of convenience, 44 | that copyright passes exclusively to Nicholas H.Tollervey on behalf of the 45 | Mu project. 46 | 47 | Checklist 48 | +++++++++ 49 | 50 | * If your contribution includes non-obvious technical decision making please 51 | make sure you document this in the 52 | `design decisions `_ 53 | section. 54 | * Your code should be commented in *plain English* (British spelling). 55 | * If your contribution is for a major block of work and you've not done so 56 | already, add yourself to the AUTHORS file following the convention found 57 | therein. 58 | * We have 100% test coverage - include tests to maintain this! 59 | * **Before submitting code ensure coding standards and test coverage by running**:: 60 | 61 | make check 62 | 63 | * If in doubt, ask a question. The only stupid question is the one that's never asked. 64 | * Most importantly, **Have fun!** :-) 65 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include mu/* 2 | include README.rst 3 | include CHANGES.rst 4 | include LICENSE 5 | include conf/* 6 | include mu/resources/css/* 7 | include mu/resources/images/* 8 | include mu/resources/fonts/* 9 | include mu/resources/pygamezero/* 10 | recursive-include mu/resources/web * 11 | include run.py 12 | recursive-include mu/locale * 13 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Mu - A Simple Python Code Editor 2 | ================================ 3 | 4 | .. image:: https://mu.readthedocs.io/en/latest/_images/logo.png 5 | 6 | Mu is a simple code editor for beginner programmers based on extensive feedback 7 | from teachers and learners. Having said that, Mu is for anyone who wants to use 8 | a simple "no frills" editor. Most importantly, have fun! 9 | 10 | Mu is a modal editor with modes for many different ways to use Python to create 11 | cool and interesting things. 12 | 13 | Mu is written in Python and works on Windows, macOS, Linux and Raspberry Pi. 14 | The project's public facing website is 15 | `https://codewith.mu/ `_. We celebrate the work done by 16 | users of mu at `https://madewith.mu/ `_. 17 | 18 | We have `extensive developer documentation `_ 19 | including a guide for 20 | `setting up a development environment `_, 21 | `contributor guidelines `_ and 22 | `some suggested first steps `_. 23 | 24 | We want our community to be a friendly place. Therefore, we expect contributors 25 | and collaborators to follow our 26 | `Code of Conduct `_. 27 | -------------------------------------------------------------------------------- /ROADMAP.rst: -------------------------------------------------------------------------------- 1 | Roadmap (Mappa MUndi) 2 | --------------------- 3 | 4 | (Apologies for the pun: https://en.wikipedia.org/wiki/Mappa_mundi) 5 | 6 | Mu started as a shonky hack. Now many people are interested in our small editor 7 | for educational use and we owe it to them to be clear what our plans are, how 8 | we work together and how *anyone* can get involved (see ``CONTRIBUTING.rst``). 9 | 10 | I believe it worth repeating the Mu philosophy we have followed so far: 11 | 12 | * Less is More: Mu has only the most essential features, so users are not 13 | intimidated by a baffling interface. 14 | * Path of Least Resistance: Whatever the task, there is always only one obvious 15 | way to do it with Mu. 16 | * Keep it Simple: It's quick and easy to learn Mu ~ complexity impedes a novice 17 | programmer's first steps. 18 | * Have fun: Learning should inspire fun ~ Mu helps learners quickly create and 19 | test working code. 20 | 21 | Python aims to make code readable, Mu aims to make it writeable. 22 | 23 | With this in mind: 24 | 25 | Next Point Release 26 | ================== 27 | 28 | 1.0.1 is a bug fix / translations release and will only include: 29 | 30 | * Update to Adafruit boards and future proofing for as-yet-unknown boards. 31 | * Swedish translation. 32 | * Updated and complete Chinese translation. 33 | * Blocking IO from Python 3 sub-process flooding data is fixed. 34 | * New MicroPython runtime for micro:bit (bug fixes). 35 | * Improvements to the stability of micro:bit flashing. 36 | 37 | Expected delivery: mid-September 2018. 38 | 39 | Next Minor Release 40 | ================== 41 | 42 | 1.1.0 will introduce some new "beta" modes: 43 | 44 | * ESP mode for embedded devices from ESP. 45 | * Web mode for creating simple dynamic websites. 46 | 47 | It will also add some new features: 48 | 49 | * Use of "black" for code style / quality checking. 50 | * Configuration of UI for purposes of better presentation: 51 | 52 | - Change size of buttons. 53 | - Tool-tips and auto-complete toggle. 54 | - Colour configuration for "Custom" theme (help dyslexic users via colour). 55 | - Transparent background (makes screen-casting easier). 56 | 57 | * Update minifier. 58 | * More translations. 59 | * Cleanups to the documentation. 60 | * Bug fix release of MicroPython for micro:bit. 61 | 62 | Expected delivery: late-November 2018. 63 | -------------------------------------------------------------------------------- /conf/90-usb-microbit.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEM=="tty", ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666" 2 | -------------------------------------------------------------------------------- /conf/mu.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | mu.codewith.editor.desktop 4 | CC0-1.0 5 | GPL-3.0 6 | Mu 7 | A simple Python editor for beginner programmers 8 | 9 |

Mu is a Python code editor for beginner programmers based on 10 | extensive feedback given by teachers and learners.

11 |

Mu is a simple code editor for beginner programmers based on the 12 | feedback given to and experiences of the Raspberry Pi Foundation's 13 | education team. Having said that, Mu is for anyone who wants to use a 14 | simple "no frills" editor.

15 |

Mu is a modal editor with modes for Adafruit's CircuitPython, the 16 | micro:bit's version of MicroPython, PyGame Zero and standard Python 3 17 | (including a graphical debugger). Some of the modes make available a 18 | REPL (either running on the connected CircuitPython or MicroPython 19 | device or as a Jupyter based iPython session in Python3 mode).

20 |

Mu is written in Python and works on Windows, OSX, Linux and 21 | Raspberry Pi.

22 |
23 | https://codewith.mu/ 24 | https://codewith.mu/tutorials/ 25 | https://github.com/mu-editor/mu/issues 26 | mu-editor 27 | Nicholas H.Tollervey 28 | mu 29 |
30 | -------------------------------------------------------------------------------- /conf/mu.codewith.editor.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=mu 4 | GenericName=A Python editor for beginner programmers 5 | Comment=A Python editor for beginner programmers 6 | Icon=mu.codewith.editor 7 | TryExec=mu-editor 8 | Exec=mu-editor %F 9 | Terminal=false 10 | Categories=Application;Development; 11 | Keywords=Python;Editor;microbit;micro:bit; 12 | StartupWMClass=mu-editor 13 | MimeType=text/x-python3;text/x-python3; 14 | -------------------------------------------------------------------------------- /conf/mu.codewith.editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/conf/mu.codewith.editor.png -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | mu (1.0.0~beta8) stretch; urgency=medium 2 | 3 | * Repackage 4 | 5 | -- Serge Schneider Tue, 26 Sep 2017 17:39:30 +0100 6 | 7 | mu (0.9.13-1) unstable; urgency=low 8 | 9 | * Add ability to change default Python directory in the settings file. Thanks to Zander Brown for the contribution. See #179. 10 | 11 | -- Nicholas Tollervey Sun, 06 Oct 2016 11:32:58 +0000 12 | 13 | mu (0.9.12-1) unstable; urgency=low 14 | 15 | * Change the default Python directory from ``~/python`` to ``~/mu_code``. This fixes issue #126. 16 | * Add instructions for installing PyQt5 and QScintilla on Mac OS. 17 | * Update to latest version of uFlash. 18 | * Add highlighting of search matches. 19 | * Check if the script produced is > 8k. 20 | * Use a settings file local to the Mu executable if available. 21 | * Fix bug with highlighting code errors in Windows. 22 | * Check to overwrite an existing file on the micro:bit FS. 23 | * Start changelog 24 | 25 | -- Nicholas Tollervey Sun, 23 Oct 2016 17:22:35 +0000 26 | 27 | mu (0.1-1) unstable; urgency=low 28 | 29 | * Initial packaging 30 | 31 | -- Alex Bradbury Fri, 25 Mar 2016 17:26:35 +0000 32 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: mu 2 | Section: python 3 | Priority: optional 4 | Maintainer: Serge Schneider 5 | Build-Depends: debhelper (>= 9), dh-python, python3-all, python3-setuptools 6 | Standards-Version: 3.9.8 7 | Homepage: https://codewith.mu/ 8 | X-Python3-Version: >= 3.2 9 | 10 | Package: mu 11 | Architecture: all 12 | Depends: ${python3:Depends}, ${misc:Depends}, python3-pyqt5.qtserialport 13 | Description: A simple editor for beginner programmers 14 | A very simple code editor for kids, teachers and beginner programmers. 15 | It's written in Python and works on Windows, OSX, Linux and Raspberry Pi. 16 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: mu 3 | Source: https://github.com/mu-editor/mu 4 | 5 | Files: * 6 | Copyright: 2015 Nicholas H.Tollervey 7 | License: GPL-3.0+ 8 | 9 | License: GPL-3.0+ 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | . 15 | This package is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | . 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | . 23 | On Debian systems, the complete text of the GNU General 24 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 25 | -------------------------------------------------------------------------------- /debian/mu.install: -------------------------------------------------------------------------------- 1 | conf/mu.codewith.editor.desktop usr/share/applications/ 2 | conf/mu.codewith.editor.png usr/share/icons/hicolor/256x256/apps/ 3 | -------------------------------------------------------------------------------- /debian/py3dist-overrides: -------------------------------------------------------------------------------- 1 | pyqt5 python3-pyqt5 2 | qscintilla python3-pyqt5.qsci 3 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export PYBUILD_NAME=mu 4 | %: 5 | dh $@ --with python3 --buildsystem=pybuild 6 | 7 | override_dh_auto_test: 8 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/source/options: -------------------------------------------------------------------------------- 1 | extend-diff-ignore = "^[^/]*[.]egg-info/" 2 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = Mu 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | Mu API Reference 2 | ---------------- 3 | 4 | This API reference is automatically generated from the docstrings found within 5 | the source code. It's meant as an easy to use and easy to share window into the 6 | code base. 7 | 8 | Take a look around! The code is simple and short. 9 | 10 | ``mu.app`` 11 | ========== 12 | 13 | The Mu application is created and configured in this module. 14 | 15 | .. automodule:: mu.app 16 | :members: 17 | 18 | ``mu.logic`` 19 | ============ 20 | 21 | Most of the fundamental logic for Mu is in this module. 22 | 23 | .. automodule:: mu.logic 24 | :members: 25 | 26 | ``mu.debugger`` 27 | =============== 28 | 29 | The debugger consists of two parts: 30 | 31 | * Client - used by Mu to process messages from the process being debugged. 32 | * Runner - created in a new process to run the code to be debugged. 33 | 34 | Messages are passed via inter-process communication. 35 | 36 | ``mu.debugger.client`` 37 | ++++++++++++++++++++++ 38 | 39 | Code used by the Mu application to communicate with the process being debugged. 40 | 41 | .. automodule:: mu.debugger.client 42 | :members: 43 | 44 | ``mu.debugger.runner`` 45 | ++++++++++++++++++++++ 46 | 47 | The runner code controls the debug process. 48 | 49 | .. automodule:: mu.debugger.runner 50 | :members: 51 | 52 | ``mu.interface`` 53 | ================ 54 | 55 | This module contains all the PyQt related code needed to create the user 56 | interface for Mu. All interaction with the user interface is done via the 57 | ``Window`` class in ``mu.interface.main``. 58 | 59 | All the other sub-modules contain different bespoke aspects of the user 60 | interface. 61 | 62 | ``mu.interface.main`` 63 | +++++++++++++++++++++ 64 | 65 | Contains the core user interface assets used by other parts of the application. 66 | 67 | .. automodule:: mu.interface.main 68 | :members: 69 | 70 | ``mu.interface.dialogs`` 71 | ++++++++++++++++++++++++ 72 | 73 | Bespoke modal dialogs required by Mu. 74 | 75 | .. automodule:: mu.interface.dialogs 76 | :members: 77 | 78 | ``mu.interface.editor`` 79 | +++++++++++++++++++++++ 80 | 81 | Contains the customised Scintilla based editor used for textual display and 82 | entry. 83 | 84 | .. automodule:: mu.interface.editor 85 | :members: 86 | 87 | ``mu.interface.panes`` 88 | ++++++++++++++++++++++ 89 | 90 | Contains code used to populate the various panes found in the user interface 91 | (REPL, file list, debug inspector etc...). 92 | 93 | .. automodule:: mu.interface.panes 94 | :members: 95 | 96 | ``mu.interface.themes`` 97 | +++++++++++++++++++++++ 98 | 99 | Theme related code so Qt changes for each pre-defined theme. 100 | 101 | .. automodule:: mu.interface.themes 102 | :members: 103 | 104 | ``mu.modes`` 105 | ============ 106 | 107 | Contains the definitions of the various modes Mu into which Mu can be put. All 108 | the core functionality is in the ``mu.modes.base`` module. 109 | 110 | ``mu.modes.base`` 111 | +++++++++++++++++ 112 | 113 | Core functionality and base classes for all Mu's modes. The definitions of 114 | API autocomplete and call tips can be found in the ``mu.modes.api`` namespace. 115 | 116 | .. automodule:: mu.modes.base 117 | :members: 118 | 119 | ``mu.modes.circuitpython`` 120 | ++++++++++++++++++++++++++ 121 | 122 | CircuitPython mode for Adafruit boards (and others). 123 | 124 | .. automodule:: mu.modes.circuitpython 125 | :members: 126 | 127 | ``mu.modes.debugger`` 128 | +++++++++++++++++++++ 129 | 130 | The Python 3 debugger mode. 131 | 132 | .. automodule:: mu.modes.debugger 133 | :members: 134 | 135 | ``mu.modes.microbit`` 136 | +++++++++++++++++++++ 137 | 138 | The original BBC micro:bit mode. 139 | 140 | .. automodule:: mu.modes.microbit 141 | :members: 142 | 143 | ``mu.modes.pygamezero`` 144 | +++++++++++++++++++++++ 145 | 146 | The Pygame Zero / pygame mode. 147 | 148 | .. automodule:: mu.modes.pygamezero 149 | :members: 150 | 151 | ``mu.modes.python3`` 152 | ++++++++++++++++++++ 153 | 154 | The Python 3 editing mode. 155 | 156 | .. automodule:: mu.modes.python3 157 | :members: 158 | 159 | ``mu.resources`` 160 | ================ 161 | 162 | Contains utility functions for working with binary assets used by Mu (mainly 163 | images). 164 | 165 | .. automodule:: mu.resources 166 | :members: 167 | -------------------------------------------------------------------------------- /docs/architecture.rst: -------------------------------------------------------------------------------- 1 | Mu's Architecture 2 | ----------------- 3 | 4 | This section provides a high level overview of how the various parts of Mu 5 | fit together. 6 | 7 | Key Concepts 8 | ============ 9 | 10 | The key concepts you should know are: 11 | 12 | * Mu uses the `PyQT5 framework `_ (that makes the `Qt `_ GUI toolkit available to Python) for making its user interface. 13 | * Mu is a modal editor: the behaviour of Mu changes, depending on mode. 14 | * There are a number of core features and behaviours that are always available and never vary, no matter the mode. 15 | * The text area into which users type code is based on a `Scintilla `_ based widget. 16 | * Mu is easy to internationalise using Python's standard ``gettext`` based modules and tools. 17 | * Mu's code base is small, well documented and has 100% unit test coverage. 18 | 19 | Code Structure 20 | ============== 21 | 22 | The code is found in the ``mu`` directory and organised in the following way: 23 | 24 | * The application is created and configured in ``app.py``. 25 | * Most of the fundamental logic for Mu is in ``logic.py``. 26 | * Un-packaged third party code used by Mu is found in ``contrib``. 27 | * The Python3 debugger consists of a debug client and debug runner found in the ``debugger`` namespace. A description of how the debugger works can be found in :doc:`debugger`. 28 | * Interacting with the UI layer is done via the ``Window`` class in the ``interface.main`` module. Mu specific UI code used by the ``Window`` class found in the other modules in the namespace. 29 | * Internationalization (I18n) related assets are found under ``locale``. Learn how this works via :doc:`translations`. 30 | * Modes are found under the ``modes`` namespace. They all inherit from a ``BaseMode`` class and there's a tutorial for :doc:`modes`. 31 | * Graphical assets, fonts and CSS descriptions for the themes are all found under ``resources``. 32 | 33 | All classes, methods and functions have documentation *written for humans*. 34 | These are extracted into the :doc:`api`. 35 | 36 | :doc:`tests` is in the ``test`` directory and filenames for tests relate 37 | directly to the file they test in the Mu code base. The module / directory 38 | structure mirrors the organisation of the Mu code base. We use PyTest's assert 39 | based unit testing. All tests have a comment describing their intent. 40 | 41 | The documentation you're reading right now (i.e. that written for developers) 42 | is found in the ``docs`` directory. We use `Sphinx `_ 43 | to write our docs and host them on `ReadTheDocs `_. 44 | Other documentation (tutorials, user help and so on) is on :doc:`website`. 45 | 46 | The ``utils`` directory contains various scripts used to scrape and / or build 47 | the API documentation used by Mu's autocomplete and call tip functionality. 48 | 49 | The other assets in the root directory of the project are mainly for 50 | documentation (such as our Code of Conduct), configuration (for testing) or 51 | packaging for various platforms (see :doc:`packaging`). 52 | 53 | If you want to make changes please read :doc:`contributing`. 54 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/awesome.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/awesome.gif -------------------------------------------------------------------------------- /docs/beautifully_useless.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/beautifully_useless.jpg -------------------------------------------------------------------------------- /docs/changes.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CHANGES.rst 2 | 3 | -------------------------------------------------------------------------------- /docs/circuit_playground.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/circuit_playground.jpg -------------------------------------------------------------------------------- /docs/code_of_conduct.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CODE_OF_CONDUCT.rst 2 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/copyright.rst: -------------------------------------------------------------------------------- 1 | Copyright Information 2 | --------------------- 3 | 4 | Mu Copyright 5 | ============ 6 | 7 | Mu, its source code and associated assets are copyright Nicholas H.Tollervey 8 | and others (those who have made significant contributions to Mu can be found in 9 | this list of :doc:`authors`). 10 | 11 | 12 | Notes on Image Copyright Status 13 | =============================== 14 | 15 | All images used in Mu's developer documentation fall under Mu's copyright 16 | status, except for the following images sourced from third parties: 17 | 18 | beautifully_useless.jpg 19 | +++++++++++++++++++++++ 20 | 21 | Permission was sought and obtained from Katerina Kamprani (the creator of 22 | `the uncomfortable `_):: 23 | 24 | Hello Nicholas, 25 | 26 | Thank you very much for asking and for your kind words. 27 | As long as there is no commercial use of the image, and since you 28 | mention my project, it is absolutely fine! 29 | I am very happy the images help to prove a point! 30 | 31 | Many greetings from Athens, Greece, 32 | Katerina 33 | 34 | circuit_playground.jpg 35 | ++++++++++++++++++++++ 36 | 37 | Permission was sought and obtained from 38 | `Adafruit Industries `_, the source of the 39 | image:: 40 | 41 | yup! 100%! please use! 42 | 43 | > Hi Folks, 44 | > 45 | > Is it OK to use a picture of a Circuit Playground Express taken 46 | > from your website in the developer docs for Mu. Like this..? 47 | > 48 | > https://mu.readthedocs.io/en/latest/modes.html#adafruit-mode 49 | 50 | pygame.png 51 | ++++++++++ 52 | 53 | Permission was sought and obtained from René Dudfield, the current core 54 | maintainer of `Pygame `_:: 55 | 56 | public domain 57 | 58 | Go for it! Feel free to do whatever weird(and not weird) things you 59 | like with it. 60 | 61 | It's a modification (by me) of a logo by Gareth Noyce, who also put 62 | the logo files in public domain. 63 | 64 | Gareth Noyce said of the logo files: 65 | They're public domain but I'd like attribution if they're used 66 | anywhere. Just a "logo by Gareth Noyce" would do, but I won't be 67 | complaining if people forget. :)' 68 | 69 | python.png 70 | ++++++++++ 71 | 72 | This is a copy of the Python logo owned by the 73 | `Python Software Foundation `_ 74 | (PSF). Mu was originally written by a PSF Fellow on behalf of the PSF as part 75 | of the PSF's contribution to the BBC's micro:bit project. Furthermore, the PSF 76 | say of the `use of the Python logo `_): 77 | 78 | "Projects and companies that use Python are encouraged to incorporate 79 | the Python logo on their websites, brochures, packaging, and elsewhere 80 | to indicate suitability for use with Python or implementation in 81 | Python. Use of the "two snakes" logo element alone, without the 82 | accompanying wordmark is permitted on the same terms as the combined 83 | logo. 84 | 85 | In general, we want the logo to be used as widely as possible to 86 | indicate use of Python or suitability for Python." 87 | 88 | lego.png 89 | ++++++++ 90 | 91 | This is a copped version of the 92 | `Creative Commons licensed `_ 93 | photograph taken by 94 | `Jeff Eaton `_ 95 | that can be `found here `_. 96 | 97 | pyboard.png 98 | +++++++++++ 99 | 100 | The `MicroPython Logo `_ 101 | is covered by the MIT license. 102 | 103 | web.png 104 | +++++++ 105 | 106 | The `Flask Logo `_ has 107 | been released to the public domain. 108 | -------------------------------------------------------------------------------- /docs/debugger-notes.log: -------------------------------------------------------------------------------- 1 | How does the Mu debugger work? 2 | ============================== 3 | 4 | The debugger has a kind of hybrid existence: it's a mode in its own right 5 | (since invoking it causes the button bar to change); but its raison d'etre 6 | is as a glorified runner for the Python3 mode. 7 | 8 | Pressing the [Debug] button in Python 3 mode calls `modes/python3.py:PythonMode.debug` 9 | which eventually calls `modes/debugger.py:DebugMode.start`. This eventually calls 10 | `main.py:Windows.add_python3_runner` in the same way as pressing the [Run] button does, but 11 | passing the `debugger=True` parameter. It then sets up and starts a 12 | `debugger/client.py:Debugger` object listening on localhost:DEBUGGER_PORT. 13 | 14 | `panes.py:PythonProcessPane.start_process` runs `mu-debug.py` with the code file 15 | as its first parameter. This basically imports and hands off to `mu/app.py.debug`. 16 | And *this* hands off to `mu/debugger/runner.py:run`. This sets up a 17 | `debugger/runner.py:Debugger` object which subclasses the stdlib `Bdb` class 18 | https://docs.python.org/3/library/bdb.html#bdb.Bdb. 19 | 20 | Meanwhile, back in Mu button-land: pressing the various [Step Into], [Step Over] 21 | etc. buttons call methods on the `debugger/client.py:Debugger` object. (eg 22 | `do_step`, `do_next`, `do_run`). These send simple messages over the socket 23 | to the listening debug runner (eg "step", "next", "continue" respectively). 24 | 25 | The debug runner operates a command buffer inside a thread from which messages 26 | are despatched via `debugger/runner.py:Debugger.interact`. (Interestingly, 27 | as far as I can tell, the command_buffer is only set up when an exception 28 | occurs to the listening thread. So, presumably, it's intended to fail on the 29 | first attempt and to set up the command buffer for the first time at that point). -------------------------------------------------------------------------------- /docs/design.rst: -------------------------------------------------------------------------------- 1 | Design Decisions 2 | ---------------- 3 | 4 | The following documents concern the decision making aspects behind various 5 | aspects of Mu. This is a recent practice (started by Tim Golden) so these 6 | documents do not cover many aspects of Mu. However, moving forward newer 7 | technical decisions will be documented in this way. 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | 12 | design/file_reading_and_writing.rst 13 | design/line-endings.rst 14 | design/runtime_virtual_environment.rst 15 | design/settings-and-sessions.rst 16 | -------------------------------------------------------------------------------- /docs/design/file_reading_and_writing.rst: -------------------------------------------------------------------------------- 1 | Reading and writing code files 2 | ============================== 3 | 4 | Decision 5 | -------- 6 | 7 | By default Mu will save files encoded as UTF-8 without a PEP 263 encoding cookie. 8 | However, if the file as loaded started with an encoding cookie, then the file 9 | will be saved again with that encoding. 10 | 11 | When reading files, Mu will detect UTF8/16 BOMs and encoding cookies. 12 | In their absence, UTF-8 will be attempted. If that fails, the OS default will 13 | be used (ie locale.getpreferredencoding()). 14 | 15 | If the file cannot be decoded according to these rules, refuse to guess. Instead, 16 | produce an informative error popup. 17 | 18 | Background 19 | ---------- 20 | 21 | Originally Mu used the built-in open() function for reading and writing its 22 | files without specifying an encoding. In that situation Python would request 23 | the preferred encoding for the locale and use that. If the user then used 24 | a character in their code which had no mapping in that encoding, the save/autosave 25 | functionality would raise an uncaught exception and the user would lose their 26 | code. 27 | 28 | Discussion and Implementation 29 | ----------------------------- 30 | 31 | It was initially suggested that we simply read/write everything as UTF-8 32 | which can encode the entire universe of Unicode codepoints. However, files 33 | which had previously been saved by Mu under a different encoding might 34 | produce mojibake or simply raise UnicodeDecodeError. 35 | 36 | To overcome the difficulty of using UTF-8 going forwards without losing backwards 37 | compatibility, the compromise was adopted of *writing* UTF-8 with an encoding 38 | cookie, while *reading* according to the rules above. 39 | 40 | It will still possible for a file to fail decoding on the way in 41 | (eg because the locale-default encoding is used, but the file is encoded otherwise). 42 | In that situation we might have attempted to reload using, eg, latin-1 which 43 | can decode every byte to *something*. But the result would have been mojibake 44 | and -- crucially -- the autosave mechanism would have kicked in 30 seconds 45 | later, overwriting the user's original file for good. 46 | 47 | Instead it was decided to offer an informative message box which could explain 48 | the situation in enough terms to offer the user a way forward without risking 49 | the integrity of their code. 50 | 51 | UPDATE: After initial implementation of the encoding cookie, it was thought 52 | that it was too arcane for beginner coders. It was decided then to save as 53 | UTF-8 by default, although without a cookie. But if a file already has an 54 | encoding cookie, that should be preserved and the encoding honoured. 55 | 56 | Implemented via: 57 | ~~~~~~~~~~~~~~~~ 58 | 59 | * https://github.com/mu-editor/mu/pull/390 60 | * https://github.com/mu-editor/mu/pull/399 61 | * https://github.com/mu-editor/mu/pull/418 62 | 63 | Discussion in: 64 | ~~~~~~~~~~~~~~ 65 | 66 | (Initial) 67 | 68 | * https://github.com/mu-editor/mu/issues/370 69 | * https://github.com/mu-editor/mu/pull/364 70 | * https://github.com/mu-editor/mu/pull/371 71 | 72 | (Later) 73 | 74 | * https://github.com/mu-editor/mu/issues/402 75 | * https://github.com/mu-editor/mu/issues/696 76 | -------------------------------------------------------------------------------- /docs/design/line-endings.rst: -------------------------------------------------------------------------------- 1 | Line-endings 2 | ============ 3 | 4 | Decision 5 | -------- 6 | 7 | Use \n internally in Mu. Detect the majority line-ending when loading a file 8 | and store it on the tab object within the editor. Then use that newline 9 | convention when saving. By default, eg for a new / empty file, use the 10 | platform line-ending. 11 | 12 | 13 | Background 14 | ---------- 15 | 16 | Mu is designed to run on any platform which supports Python / Qt. This includes 17 | Windows and any \*nix variant, including OS/X. Windows traditionally uses \r\n 18 | (ASCII 13 + ASCII 10) for line-endings while \*nix usually recognises a single 19 | \n (ASCII 10). Although many editors now detect and adapt to either convention, 20 | it's common enough for beginners to use, eg, Windows notepad which only honours 21 | and only generates the \r\n convention. 22 | 23 | When reading / writing files, Python offers several forms of line-ending 24 | manipulation via the newline= parameter in the built-in open() function. 25 | Mu originally used Universal newlines (newline=None; the default), but then 26 | switched to retaining newlines (newline="") in PR #133 27 | 28 | The effect of this last change is to retain whatever convention or mix of 29 | conventions is present in the source file. In effect it is overriding any 30 | newline manipulation to present to the editor control the characters originally 31 | present in the file. When the file is saved, the same characters are written 32 | out. 33 | 34 | However this creates a quandary when programmatically manipulating the editor 35 | text: do we use the most widespread \n as a line-ending; or do we use the 36 | platform convention `os.linesep`; or do we use the convention used in the 37 | file itself, which may or may not follow the platform convention? 38 | 39 | 40 | Discussion and Implementation 41 | ----------------------------- 42 | 43 | My proposal here is that Mu operate its own line-ending manipulation. 44 | 45 | When reading the file, note the majority line-ending convention but 46 | convert wholly to \n. When writing the file, use the convention noted 47 | on the way in. This is essentially the same as we would do when reading 48 | encoded Unicode from a file. 49 | 50 | This way the line-endings are honoured so that, eg, a file can be read/written 51 | in Notepad without problems. And the Mu code can be sure of using 52 | \n as a line-ending convention when manipulating the text. 53 | 54 | In terms of the current implementation, the convention from the incoming 55 | file could presumably be stored on the tab object. 56 | 57 | Implemented via: 58 | ~~~~~~~~~~~~~~~~ 59 | 60 | * https://github.com/mu-editor/mu/pull/390 61 | * https://github.com/mu-editor/mu/pull/399 62 | 63 | Discussion in: 64 | ~~~~~~~~~~~~~~ 65 | 66 | * (original change) https://github.com/mu-editor/mu/pull/133 67 | * https://github.com/mu-editor/mu/pull/371 68 | * https://github.com/mu-editor/mu/issues/380 69 | -------------------------------------------------------------------------------- /docs/design/runtime_virtual_environment.rst: -------------------------------------------------------------------------------- 1 | Run the user's code inside its own virtual environment 2 | ====================================================== 3 | 4 | Decision 5 | -------- 6 | 7 | Mu, whether pip-installed or via installer will maintain a separate virtual 8 | environment for running the user's code. Initially this will contain all 9 | the dependencies used by any of our modes, plus any packages the user 10 | installs in addition. 11 | 12 | The dependencies needed for the running of the editor itself (mostly PyQt 13 | stuff but currently including some serial packages which have "leaked" from 14 | the modes) will be kept in a separate environment, virtual or otherwise. 15 | 16 | The installers will have to support this approach by bundling wheels (as 17 | our assumption is that some schools at least will have restricted or no 18 | internet access). 19 | 20 | For now we're not breaking out modes into plugins or separate environments 21 | although that's a natural extension of this work. If that were done later, 22 | each mode could specify its own dependencies which could be installed on 23 | demand. 24 | 25 | Background 26 | ---------- 27 | 28 | * Getting Mu to unpack and run out of the box on the three main platforms: 29 | Windows, OS X & Linux has always proven challenging. 30 | * In addition, within the Mu codebase, the code to run the user's code is 31 | scattered and contains a fragile re-implementation of a virtual environment. 32 | * Installing 3rd-party modules was also a little fragile as we had to run 33 | `pip` with a `--target` parameter 34 | * There are other issues, especially around the Jupyter console and, on 35 | Windows, its use of the pywin32 packages which have slightly odd path 36 | handling. 37 | 38 | Discussion and Implementation 39 | ----------------------------- 40 | 41 | This started off with work by @ntoll to have the 3rd-party apps installed 42 | into a virtual environment rather than with the `--target` parameter which 43 | would try to force them into a directory where Mu could find them. This 44 | stalled somewhat, especially on Windows, and I (@tjguk) took over that 45 | branch. 46 | 47 | Having focused on the getting a virtual environment running for the 3rd-party 48 | installs, I realised that having a venv for the whole of the code runtime 49 | might help solve some of the other issues. After a few merges to get some 50 | changes in, especially those by @tmontes to the installer, we started PR#1072 51 | https://github.com/mu-editor/mu/pull/1072. 52 | 53 | There is now a `virtual_environment.py` module which initially brings together 54 | various pieces of code which were scattered around the codebase and adds 55 | support for creating and installing into a virtual environment. The various 56 | places where the user code is run (mostly within the `modes` package, but including 57 | inside `panes.py`) have been updated to use this virtual environment logic. 58 | Possible future work might involve adding a "run process" method to the class 59 | itself. 60 | 61 | As far as possible this should remove the need to hack up special `PYTHONPATH`, 62 | `*.pth` and `site.py` logic. 63 | 64 | Implemented via: 65 | ~~~~~~~~~~~~~~~~ 66 | 67 | * https://github.com/mu-editor/mu/pull/1068 68 | * https://github.com/mu-editor/mu/pull/1072 69 | * https://github.com/mu-editor/mu/pull/1056 70 | * https://github.com/mu-editor/mu/pull/1058 71 | 72 | Discussion in: 73 | ~~~~~~~~~~~~~~ 74 | 75 | * https://github.com/mu-editor/mu/issues/1061 76 | * https://github.com/mu-editor/mu/issues/1070 77 | -------------------------------------------------------------------------------- /docs/design/template-decision.txt: -------------------------------------------------------------------------------- 1 | Meaningful Title 2 | ================ 3 | 4 | Decision 5 | -------- 6 | 7 | A brief summary of what Mu does given the context of the title. 8 | 9 | 10 | Background 11 | ---------- 12 | 13 | As many paragraphs as needed to describe the situation that caused this 14 | decision to be made. 15 | 16 | 17 | Discussion and Implementation 18 | ----------------------------- 19 | 20 | As many paragraphs as needed to explain the approach taken and implementation 21 | thereof. 22 | 23 | Implemented via: 24 | ~~~~~~~~~~~~~~~~ 25 | 26 | * (A list of URLs to GitHub pull requests or Git commits.) 27 | * https://github.com/mu-editor/mu/pull/390 28 | 29 | Discussion in: 30 | ~~~~~~~~~~~~~~ 31 | 32 | * (A list of URLs to GitHub issues, mailing list discussions etc...) 33 | * https://github.com/mu-editor/mu/issues/380 34 | -------------------------------------------------------------------------------- /docs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon.png -------------------------------------------------------------------------------- /docs/icon_brief/debug-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/debug-icons.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-adafruit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-adafruit.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-annotated_ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-annotated_ui.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-high-contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-high-contrast.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-microbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-microbit.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-mode-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-mode-select.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-python.png -------------------------------------------------------------------------------- /docs/icon_brief/mu-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_brief/mu-running.png -------------------------------------------------------------------------------- /docs/icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/icon_small.png -------------------------------------------------------------------------------- /docs/jupyter-notes.log: -------------------------------------------------------------------------------- 1 | My notes while trying to understand our use of the Jupyter kernel 2 | 3 | * IPython can be run as [I think] an external "kernel", processing instructions 4 | and providing output. This is how the Jupyter notebooks operate: by providing 5 | a front-end to the IPython kernel backend 6 | 7 | * We use this via a QtConsole widget which -- in ways that I'm still exploring -- 8 | operates as a Qt widget, slotting into our setup as a Pane -- while talking to 9 | and from the backend kernel. There are two processes which talk via ZMQ 10 | 11 | * Useful docs on QtConsole here: https://qtconsole.readthedocs.io/en/stable/ 12 | 13 | * We use the RichJupyterWidget from qtconsole.rich_jupyter_widget. This is 14 | mentioned here: 15 | 16 | https://qtconsole.readthedocs.io/en/stable/#embedding-the-qtconsole-in-a-qt-application 17 | 18 | and there's an example here: 19 | 20 | https://github.com/jupyter/qtconsole/blob/master/examples/embed_qtconsole.py 21 | 22 | * The heavy lifting for the RichJupyterWidget is all done in: 23 | 24 | https://github.com/jupyter/qtconsole/blob/master/qtconsole/jupyter_widget.py 25 | 26 | which, in turn, leans on: 27 | 28 | https://github.com/jupyter/qtconsole/blob/master/qtconsole/frontend_widget.py 29 | 30 | * We start the kernel inside modes/python3.py:KernelRunner.start_kernel 31 | The QtKernelManager is inside qtconsole.manager which leans on KernelManager 32 | from jupyter_client\manager.py. This does *actually* manage the kernel, but 33 | for launching, leans on jupyter_client\launcher.py:launch_kernel 34 | 35 | QUESTIONS 36 | --------- 37 | 38 | * Do we need / make use of the extra complexity this brings? It has layer upon 39 | layer, all of which we need to adapt for our particular situation. 40 | 41 | * It looks as if the QtConsole offers functionality similar to the Jupyter 42 | notebooks, with graphs and so on. But do we need this? 43 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo.png -------------------------------------------------------------------------------- /docs/logo_design/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/logo.png -------------------------------------------------------------------------------- /docs/logo_design/mu-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/mu-logo-large.png -------------------------------------------------------------------------------- /docs/logo_design/mu-logo-large.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/mu-logo-large.xcf -------------------------------------------------------------------------------- /docs/logo_design/mu-logo-nocap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /docs/logo_design/mu-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/mu-logo.png -------------------------------------------------------------------------------- /docs/logo_design/mu-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 26 | 28 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/logo_design/pythonic_world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/pythonic_world.jpg -------------------------------------------------------------------------------- /docs/logo_design/red_python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/red_python.png -------------------------------------------------------------------------------- /docs/logo_design/splash-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/splash-screen.png -------------------------------------------------------------------------------- /docs/logo_design/splash.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/splash.xcf -------------------------------------------------------------------------------- /docs/logo_design/world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/world.jpg -------------------------------------------------------------------------------- /docs/logo_design/world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/logo_design/world.png -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=Mu 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/microbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/microbit.png -------------------------------------------------------------------------------- /docs/mu-debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/mu-debugger.png -------------------------------------------------------------------------------- /docs/mu-startup-notes.log: -------------------------------------------------------------------------------- 1 | * Main entry point -> app.py:run 2 | either via -m or via run.py or via the installed launcher 3 | * Steps: 4 | - set up logging 5 | - create QApplication 6 | - create core Window (ultimately from interface\main.py:Window) 7 | - use a closure to add a callback for the Window's load_theme [not clear why] 8 | - create a logical editor (from logic.py:Editor) passing the core Window as its "view" 9 | - set up the editor (via logic.py\Editor:setup), secondarily setting up modes (via app.py:setup_modes) 10 | - throw in various connectors to the editor window 11 | - throw up a splash screen for 2 secs 12 | - run the app 13 | * Logical editor setup (in logic.py:__init__ & setup) 14 | - Reset the theme, the mode, the list of modes, the microbit runtime, list of 15 | connected devices, 16 | -------------------------------------------------------------------------------- /docs/mu_sketch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/mu_sketch.jpg -------------------------------------------------------------------------------- /docs/pygame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/pygame.png -------------------------------------------------------------------------------- /docs/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/python.png -------------------------------------------------------------------------------- /docs/roadmap.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../ROADMAP.rst 2 | 3 | -------------------------------------------------------------------------------- /docs/swag/t-shirts/Baby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Baby.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/Carlos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Carlos.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/Daniel Pope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Daniel Pope.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/Lady Ada.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Lady Ada.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/Phil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Phil.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/Stig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Stig.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/Stig.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Stig 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/swag/t-shirts/Tim Golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/Tim Golden.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/arrr.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/arrr.svg.png -------------------------------------------------------------------------------- /docs/swag/t-shirts/philbin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/docs/swag/t-shirts/philbin.png -------------------------------------------------------------------------------- /docs/tests.rst: -------------------------------------------------------------------------------- 1 | Mu's Test Suite 2 | --------------- 3 | 4 | We have tests so we can make changes with confidence. 5 | 6 | We use several different sorts of test: 7 | 8 | * `PyFlakes `_ for checking for errors in 9 | our code. 10 | * `pycodestyle `_ for 11 | making sure our coding style conforms with most of the conventions of 12 | `PEP8 `_. 13 | * `PyTest `_ as a framework for 14 | writing our unit tests. 15 | * `Coverage `_ for checking 16 | the coverage of our unit tests. 17 | 18 | .. warning:: 19 | 20 | We currently have 100% test coverage. 21 | 22 | It means **every line of code in Mu has been exercised by at least one 23 | unit test**. We would like to keep it this way! 24 | 25 | We can't claim that Mu is bug-free, but we can claim that we've expressed 26 | an opinion about how every line of code should behave. Furthermore, our 27 | opinion of how such code behaves may **NOT** be accurate or even 28 | desirable. ;-) 29 | 30 | In addition, we regularly make use of the excellent 31 | `LGTM `_ online code quality service 32 | written, in part, by friend-of-Mu, 33 | `Dr.Mark Shannon `_. 34 | 35 | Running the Tests 36 | +++++++++++++++++ 37 | 38 | Running the tests couldn't be simpler: just use the ``make`` command:: 39 | 40 | $ make check 41 | 42 | This will run **ALL** the tests of each type. 43 | 44 | To run specific types of test please try: ``make pyflakes``, 45 | ``make pycodestyle``, ``make test`` or ``make coverage``. 46 | 47 | .. warning:: 48 | 49 | The test suite will only work if you have installed all the requirements 50 | for developing Mu. 51 | 52 | Please see :doc:`setup` for more information on how to achieve this. 53 | 54 | Writing a New Test 55 | ++++++++++++++++++ 56 | 57 | All the unit tests are in the ``tests`` subdirectory in the root of Mu's 58 | repository. The tests are organised to mirror the code structure of the 59 | application itself. For example, the tests for the ``mu.modes.base`` 60 | namespace are in the ``tests.modes.test_base.py`` file. 61 | 62 | As mentioned above, we use PyTest as a framework for writing our unit tests. 63 | Please refer to their 64 | `extensive documentation `_ for more 65 | details. 66 | 67 | In terms of our expectation for writing a test, we expect it to look something 68 | like the following:: 69 | 70 | def test_MyClass_function_name_extra_info(): 71 | """ 72 | This is a description of the INTENTION of the test. For 73 | example, we may want to know why this test is important, 74 | any special context information and even a reference to a 75 | bug report if required. 76 | """ 77 | assert True # As per PyTest conventions, use simple asserts. 78 | 79 | We also expect your test code to pass PyFlakes and PEP checks. If in doubt, 80 | don't hesitate to get in touch and ask. 81 | -------------------------------------------------------------------------------- /docs/translations.rst: -------------------------------------------------------------------------------- 1 | Internationalisation of Mu 2 | ========================== 3 | 4 | A really useful and relatively simple way to contribute to Mu is to translate 5 | the user interface into a different language. The steps to do this are very 6 | simple and there exist plenty of tools to help you. 7 | 8 | You can contribute in three ways: 9 | 10 | * Improve or extend an existing translation. 11 | * Create a completely new translation for a new language. 12 | * Make a translation of `Mu's website `_ (see the 13 | :doc:`website` guide for how to do this). 14 | 15 | In both cases you'll be using assets found in the ``mu/locale`` directory. 16 | 17 | Mu uses Python's standard `gettext `_ 18 | based internationalization API so we can make use of standard tools to help 19 | translators, such as `babel `_ or 20 | `Poedit `_. 21 | 22 | .. admonition:: Non-technical users 23 | 24 | If you are not a technical user and you are not familiar with the 25 | tools and jargon we use in this guide, 26 | please reach out to us by 27 | `creating a new issue in GitHub `_. 28 | 29 | We will help you set up a user-friendly tool that you can use to 30 | contribute new or improved translations, and integrate them into the next 31 | Mu release. 32 | 33 | We welcome translations from all users! 34 | 35 | 36 | 37 | How To 38 | ------ 39 | 40 | Updating or creating a new translation for Mu's user interface requires 41 | :doc:`setting up a development environment ` beforehand and, 42 | from there, 43 | is a four-step process: 44 | 45 | 46 | 1. Produce an up to date ``mu.po`` file 47 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 48 | 49 | Open a CLI shell, 50 | change the working directory to Mu's repository root, 51 | and run:: 52 | 53 | $ make translate_begin LANG=xx_XX 54 | 55 | Where ``xx_XX`` is the identifier for the target language. 56 | 57 | This creates (or updates, if it already exists) the ``mu.po`` file under the 58 | ``mu/locale/xx_XX/LC_MESSAGES/`` directory -- 59 | this is where the original British English messages 60 | are associated with their localized translations. 61 | 62 | 63 | 2. Translate Mu user interface strings 64 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 65 | 66 | Use a tool of your choice to edit the ``mu.po`` file: 67 | 68 | * Those looking for a GUI based tool can try out `Poedit `__. 69 | * Others might prefer a plain text editor, which will be sufficient. 70 | 71 | 72 | 3. Check the translation result 73 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 74 | 75 | As you progress, 76 | check the translation results by launching Mu with:: 77 | 78 | $ make translate_test LANG=xx_XX 79 | 80 | As before, 81 | ``xx_XX`` is the identifier for the target language. 82 | 83 | When done checking, 84 | quit Mu, 85 | and go back to step 2. as many times as needed. 86 | 87 | 88 | 4. Submit your translation work 89 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 90 | 91 | This process produced two new or updated files, 92 | both under the ``mu/locale/xx_XX/LC_MESSAGES/`` directory: 93 | 94 | * ``mu.po`` containing the text based source of the translation strings. 95 | * ``mu.mo`` containing a compiled version of the above, used by Mu at runtime. 96 | 97 | Commit your changes and create a pull request via GitHub. 98 | 99 | Thanks! 100 | -------------------------------------------------------------------------------- /make.cmd: -------------------------------------------------------------------------------- 1 | python make.py %* -------------------------------------------------------------------------------- /mu/__init__.py: -------------------------------------------------------------------------------- 1 | # IMPORTANT 2 | # --------- 3 | # Keep these metadata assignments simple and single-line. They are parsed 4 | # somewhat naively by setup.py and the Windows installer generation script. 5 | 6 | __title__ = "mu-editor" 7 | __description__ = "A simple Python editor for beginner programmers." 8 | 9 | __version__ = "1.2.2" 10 | 11 | __license__ = "GPL3" 12 | __url__ = "https://github.com/mu-editor/mu" 13 | 14 | __author__ = "Nicholas H.Tollervey" 15 | __email__ = "ntoll@ntoll.org" 16 | -------------------------------------------------------------------------------- /mu/__main__.py: -------------------------------------------------------------------------------- 1 | from mu.app import run 2 | 3 | 4 | def main(): 5 | run() 6 | 7 | 8 | if __name__ == "__main__": 9 | main() 10 | -------------------------------------------------------------------------------- /mu/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import platformdirs 4 | 5 | # The default directory for application data (i.e., configuration). 6 | DATA_DIR = platformdirs.user_data_dir(appname="mu", appauthor="python") 7 | 8 | # The name of the default virtual environment used by Mu. 9 | VENV_NAME = "mu_venv" 10 | 11 | # The directory containing default virtual environment. 12 | VENV_DIR = os.path.join(DATA_DIR, VENV_NAME) 13 | 14 | # Maximum line length for using both in Check and Tidy 15 | MAX_LINE_LENGTH = 88 16 | 17 | # The user's home directory. 18 | HOME_DIRECTORY = os.path.expanduser("~") 19 | 20 | # Name of the directory within the home folder to use by default 21 | WORKSPACE_NAME = "mu_code" 22 | -------------------------------------------------------------------------------- /mu/contrib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/contrib/__init__.py -------------------------------------------------------------------------------- /mu/debugger/config.py: -------------------------------------------------------------------------------- 1 | # Port number for debugger. 2 | DEBUGGER_PORT = 31415 3 | -------------------------------------------------------------------------------- /mu/debugger/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Debug related utility functions for the Mu editor. 3 | 4 | Copyright (c) Nicholas H.Tollervey and others (see the AUTHORS file). 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | """ 19 | 20 | 21 | def is_breakpoint_line(code): 22 | """ 23 | Return a boolean indication if the specified code from a single line can 24 | have a breakpoint added to it. 25 | 26 | Based entirely on simple but effective heuristics (see comments). 27 | """ 28 | code = code.strip() 29 | if not code: 30 | return False 31 | # Can't set breakpoints on blank lines or comments. 32 | # TODO: Make this more robust. 33 | if code[0] == "#" or code[:3] == '"""' or code[:3] == "'''": 34 | return False 35 | # Can't set breakpoints on lines that end with opening (, { or [ 36 | if code[-1] in ("(", "{", "["): 37 | return False 38 | # Can't set breakpoints on lines that contain only closing ), } or ] 39 | if len(code) == 1 and code in (")", "}", "]"): 40 | return False 41 | return True 42 | -------------------------------------------------------------------------------- /mu/i18n.py: -------------------------------------------------------------------------------- 1 | import os 2 | import gettext 3 | 4 | from PyQt5.QtCore import QLocale 5 | 6 | # DEBUG/TRANSLATE: override the language code here (e.g. to Chinese). 7 | # language_code = 'zh' 8 | language_code = QLocale.system().name() 9 | 10 | # Configure locale and language 11 | # Define where the translation assets are to be found. 12 | localedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "locale")) 13 | gettext.translation( 14 | "mu", localedir=localedir, languages=[language_code], fallback=True 15 | ).install() 16 | 17 | 18 | def set_language(language_code, localedir=localedir): 19 | """ 20 | Utility function to allow admin pane updates to change the locale. 21 | """ 22 | gettext.translation( 23 | "mu", localedir=localedir, languages=[language_code], fallback=True 24 | ).install() 25 | -------------------------------------------------------------------------------- /mu/interface/__init__.py: -------------------------------------------------------------------------------- 1 | from .main import Window 2 | 3 | 4 | __all__ = ["Window"] 5 | -------------------------------------------------------------------------------- /mu/locale/de_DE/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/de_DE/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/es/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/es/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/fr/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/fr/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/ja/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/ja/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/nl/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/nl/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/pl/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/pl/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/pt_BR/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/pt_BR/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/pt_PT/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/pt_PT/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/ru_RU/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/ru_RU/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/sk_SK/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/sk_SK/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/sv/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/sv/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/uk_UA/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/uk_UA/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/vi/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/vi/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/locale/zh_CN/LC_MESSAGES/mu.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/locale/zh_CN/LC_MESSAGES/mu.mo -------------------------------------------------------------------------------- /mu/modes/__init__.py: -------------------------------------------------------------------------------- 1 | from .python3 import PythonMode 2 | from .circuitpython import CircuitPythonMode 3 | from .microbit import MicrobitMode 4 | from .debugger import DebugMode 5 | from .pygamezero import PyGameZeroMode 6 | from .snek import SnekMode 7 | from .esp import ESPMode 8 | from .web import WebMode 9 | from .pyboard import PyboardMode 10 | from .lego import LegoMode 11 | from .pico import PicoMode 12 | 13 | __all__ = [ 14 | "PythonMode", 15 | "CircuitPythonMode", 16 | "MicrobitMode", 17 | "DebugMode", 18 | "PyGameZeroMode", 19 | "SnekMode", 20 | "ESPMode", 21 | "WebMode", 22 | "PyboardMode", 23 | "LegoMode", 24 | "PicoMode", 25 | ] 26 | -------------------------------------------------------------------------------- /mu/modes/api/__init__.py: -------------------------------------------------------------------------------- 1 | from .adafruit import ADAFRUIT_APIS 2 | from .microbit import MICROBIT_APIS 3 | from .python3 import PYTHON3_APIS 4 | from .pi import PI_APIS 5 | from .shared import SHARED_APIS 6 | from .pygamezero import PYGAMEZERO_APIS 7 | from .snek import SNEK_APIS 8 | from .esp import ESP_APIS 9 | from .flask import FLASK_APIS 10 | from .pyboard import PYBOARD_APIS 11 | from .lego import LEGO_APIS 12 | 13 | __all__ = [ 14 | "ADAFRUIT_APIS", 15 | "MICROBIT_APIS", 16 | "PYTHON3_APIS", 17 | "PI_APIS", 18 | "SHARED_APIS", 19 | "PYGAMEZERO_APIS", 20 | "SNEK_APIS", 21 | "ESP_APIS", 22 | "FLASK_APIS", 23 | "PYBOARD_APIS", 24 | "LEGO_APIS", 25 | ] 26 | -------------------------------------------------------------------------------- /mu/modes/lego.py: -------------------------------------------------------------------------------- 1 | """ 2 | A mode for working with Lego Spike boards running MicroPython. 3 | 4 | Copyright (c) 2015-2019 Nicholas H.Tollervey and others (see the AUTHORS file). 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | """ 19 | import logging 20 | from mu.modes.esp import ESPMode 21 | from mu.modes.api import LEGO_APIS, SHARED_APIS 22 | 23 | 24 | logger = logging.getLogger(__name__) 25 | 26 | 27 | class LegoMode(ESPMode): 28 | """ 29 | Represents the functionality required for running MicroPython on Lego Spike 30 | boards. This is simply a modified version of the ESP mode. 31 | """ 32 | 33 | name = _("Lego MicroPython") 34 | short_name = "lego" 35 | board_name = "Lego Spike" 36 | description = _("Write MicroPython directly on Lego Spike devices.") 37 | icon = "lego" 38 | fs = None 39 | 40 | valid_boards = [ 41 | # VID , PID, Manufacturer string, Device name 42 | (0x0694, 0x0009, None, "Lego Spike"), # Lego Spike board only. 43 | ] 44 | 45 | def api(self): 46 | """ 47 | Return a list of API specifications to be used by auto-suggest and call 48 | tips. 49 | """ 50 | return SHARED_APIS + LEGO_APIS 51 | -------------------------------------------------------------------------------- /mu/modes/pico.py: -------------------------------------------------------------------------------- 1 | """ 2 | A mode for working with Raspberry Pi Pico running MicroPython. 3 | 4 | Copyright (c) 2020 Nicholas H.Tollervey and others (see the AUTHORS file). 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | """ 19 | import logging 20 | from mu.modes.esp import ESPMode 21 | from mu.modes.api import SHARED_APIS # TODO: Work out Pico APIs 22 | 23 | 24 | logger = logging.getLogger(__name__) 25 | 26 | 27 | class PicoMode(ESPMode): 28 | """ 29 | Represents the functionality required for running MicroPython on a 30 | Raspberry Pi Pico board. This is simply a modified version of the ESP mode. 31 | """ 32 | 33 | name = _("RP2040") 34 | short_name = "pico" 35 | board_name = "Raspberry Pi Pico" 36 | description = _("Write MicroPython directly on a Raspberry Pi Pico.") 37 | icon = "pico" 38 | fs = None 39 | 40 | valid_boards = [ 41 | # VID , PID, Manufacturer string, Device name 42 | (0x2E8A, 0x0005, None, "Raspberry Pi Pico"), 43 | ] 44 | 45 | def api(self): 46 | """ 47 | Return a list of API specifications to be used by auto-suggest and call 48 | tips. 49 | """ 50 | return SHARED_APIS 51 | -------------------------------------------------------------------------------- /mu/mu_debug.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from mu.debugger.config import DEBUGGER_PORT 4 | import mu.debugger.runner 5 | 6 | if sys.platform == "win32" and "pythonw.exe" in sys.executable: 7 | # Add the python**.zip path to sys.path if running from the version of Mu 8 | # installed via the official Windows installer. 9 | # See: #612 and #581 for context. 10 | py_dir = os.path.dirname(sys.executable) 11 | version = "{}{}".format(*sys.version_info[:2]) 12 | zip_file = "python{}.zip".format(version) 13 | path_to_add = os.path.normcase(os.path.join(py_dir, zip_file)) 14 | if os.path.exists(path_to_add): 15 | sys.path.append(path_to_add) 16 | 17 | 18 | def debug(filename=None, *args): 19 | """ 20 | Create a debug runner in a new process. 21 | 22 | This is what the Mu debugger will drive. Uses the filename and associated 23 | args found in sys.argv. 24 | """ 25 | if filename is None: 26 | print("Debugger requires a Python script filename to run.") 27 | else: 28 | filepath = os.path.normcase(os.path.abspath(filename)) 29 | mu.debugger.runner.run("localhost", DEBUGGER_PORT, filepath, args) 30 | 31 | 32 | if __name__ == "__main__": 33 | debug(*sys.argv[1:]) 34 | -------------------------------------------------------------------------------- /mu/resources/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2015-2017 Nicholas H.Tollervey and others (see the AUTHORS file). 3 | 4 | Based upon work done for Puppy IDE by Dan Pope, Nicholas Tollervey and Damien 5 | George. 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | """ 20 | from pkg_resources import resource_filename, resource_string 21 | from PyQt5.QtGui import QPixmap, QIcon, QMovie 22 | from PyQt5.QtCore import QDir 23 | import os 24 | 25 | 26 | # The following lines add the images and css directories to the search path. 27 | QDir.addSearchPath("images", resource_filename(__name__, "images")) 28 | QDir.addSearchPath("css", resource_filename(__name__, "css")) 29 | 30 | 31 | def path(name, resource_dir="images/", ext=""): 32 | """Return the filename for the referenced image.""" 33 | return resource_filename(__name__, resource_dir + name + ext) 34 | 35 | 36 | def load_icon(name): 37 | """Load an icon from the resources directory.""" 38 | svg_path = path(name, ext=".svg") 39 | if os.path.exists(svg_path): 40 | svg_icon = QIcon(svg_path) 41 | if svg_icon: 42 | return svg_icon 43 | return QIcon(path(name)) 44 | 45 | 46 | def load_pixmap(name, size=None): 47 | """Load a pixmap from the resources directory.""" 48 | if size is not None: 49 | icon = load_icon(name) 50 | return icon.pixmap(size) 51 | return QPixmap(path(name)) 52 | 53 | 54 | def load_movie(name): 55 | """Load an animated GIF from the resources directory.""" 56 | return QMovie(path(name)) 57 | 58 | 59 | def load_stylesheet(name): 60 | """Load a CSS stylesheet from the resources directory.""" 61 | return resource_string(__name__, "css/" + name).decode("utf8") 62 | 63 | 64 | def load_font_data(name): 65 | """ 66 | Load the (binary) content of a font as bytes 67 | """ 68 | return resource_string(__name__, "fonts/" + name) 69 | -------------------------------------------------------------------------------- /mu/resources/fonts/SourceCodePro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/fonts/SourceCodePro-Bold.otf -------------------------------------------------------------------------------- /mu/resources/fonts/SourceCodePro-BoldIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/fonts/SourceCodePro-BoldIt.otf -------------------------------------------------------------------------------- /mu/resources/fonts/SourceCodePro-It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/fonts/SourceCodePro-It.otf -------------------------------------------------------------------------------- /mu/resources/fonts/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/fonts/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /mu/resources/fonts/SourceCodePro-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/fonts/SourceCodePro-Semibold.otf -------------------------------------------------------------------------------- /mu/resources/fonts/SourceCodePro-SemiboldIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/fonts/SourceCodePro-SemiboldIt.otf -------------------------------------------------------------------------------- /mu/resources/images/browse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/browse.png -------------------------------------------------------------------------------- /mu/resources/images/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/button.png -------------------------------------------------------------------------------- /mu/resources/images/button.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 45 | 52 | 59 | 60 | 62 | 63 | 65 | image/svg+xml 66 | 68 | 69 | 70 | 71 | 72 | 77 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /mu/resources/images/check-bad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/check-bad.png -------------------------------------------------------------------------------- /mu/resources/images/check-good.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/check-good.png -------------------------------------------------------------------------------- /mu/resources/images/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/check.png -------------------------------------------------------------------------------- /mu/resources/images/checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/checked.png -------------------------------------------------------------------------------- /mu/resources/images/checked.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/circuitpython.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/circuitpython.png -------------------------------------------------------------------------------- /mu/resources/images/close-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 42 | 45 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /mu/resources/images/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/css.png -------------------------------------------------------------------------------- /mu/resources/images/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/debug.png -------------------------------------------------------------------------------- /mu/resources/images/deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/deploy.png -------------------------------------------------------------------------------- /mu/resources/images/document-dirty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 42 | 45 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /mu/resources/images/document.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /mu/resources/images/dropdown-arrow-contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/dropdown-arrow-contrast.png -------------------------------------------------------------------------------- /mu/resources/images/dropdown-arrow-contrast.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/dropdown-arrow-night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/dropdown-arrow-night.png -------------------------------------------------------------------------------- /mu/resources/images/dropdown-arrow-night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/dropdown-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/dropdown-arrow.png -------------------------------------------------------------------------------- /mu/resources/images/dropdown-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/esp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/esp.png -------------------------------------------------------------------------------- /mu/resources/images/files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/files.png -------------------------------------------------------------------------------- /mu/resources/images/flash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/flash.png -------------------------------------------------------------------------------- /mu/resources/images/fonts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/fonts.png -------------------------------------------------------------------------------- /mu/resources/images/fonts.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /mu/resources/images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/help.png -------------------------------------------------------------------------------- /mu/resources/images/help.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 94 | 99 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /mu/resources/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/icon.png -------------------------------------------------------------------------------- /mu/resources/images/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 11 | 13 | 20 | 25 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /mu/resources/images/images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/images.png -------------------------------------------------------------------------------- /mu/resources/images/images.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 94 | 99 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /mu/resources/images/language.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 17 | 22 | 26 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /mu/resources/images/lego.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/lego.png -------------------------------------------------------------------------------- /mu/resources/images/load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/load.png -------------------------------------------------------------------------------- /mu/resources/images/logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/logs.png -------------------------------------------------------------------------------- /mu/resources/images/logs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/microbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/microbit.png -------------------------------------------------------------------------------- /mu/resources/images/modes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/modes.png -------------------------------------------------------------------------------- /mu/resources/images/modes.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 94 | 99 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /mu/resources/images/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/music.png -------------------------------------------------------------------------------- /mu/resources/images/music.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /mu/resources/images/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/new.png -------------------------------------------------------------------------------- /mu/resources/images/new.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /mu/resources/images/pico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/pico.png -------------------------------------------------------------------------------- /mu/resources/images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/play.png -------------------------------------------------------------------------------- /mu/resources/images/plotter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/plotter.png -------------------------------------------------------------------------------- /mu/resources/images/plotter.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /mu/resources/images/pyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/pyboard.png -------------------------------------------------------------------------------- /mu/resources/images/pygamezero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/pygamezero.png -------------------------------------------------------------------------------- /mu/resources/images/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/python.png -------------------------------------------------------------------------------- /mu/resources/images/quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/quit.png -------------------------------------------------------------------------------- /mu/resources/images/repl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/repl.png -------------------------------------------------------------------------------- /mu/resources/images/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/run.png -------------------------------------------------------------------------------- /mu/resources/images/run.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /mu/resources/images/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/save.png -------------------------------------------------------------------------------- /mu/resources/images/scroll-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/scroll-down.png -------------------------------------------------------------------------------- /mu/resources/images/scroll-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/scroll-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/scroll-left.png -------------------------------------------------------------------------------- /mu/resources/images/scroll-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/scroll-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/scroll-right.png -------------------------------------------------------------------------------- /mu/resources/images/scroll-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/scroll-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/scroll-up.png -------------------------------------------------------------------------------- /mu/resources/images/scroll-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /mu/resources/images/serial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/serial.png -------------------------------------------------------------------------------- /mu/resources/images/snippets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/snippets.png -------------------------------------------------------------------------------- /mu/resources/images/sounds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/sounds.png -------------------------------------------------------------------------------- /mu/resources/images/splash-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/splash-screen.png -------------------------------------------------------------------------------- /mu/resources/images/splash_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/splash_fail.png -------------------------------------------------------------------------------- /mu/resources/images/splash_screen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/splash_screen.gif -------------------------------------------------------------------------------- /mu/resources/images/splash_screen.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/splash_screen.xcf -------------------------------------------------------------------------------- /mu/resources/images/splash_screen_base_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/splash_screen_base_image.png -------------------------------------------------------------------------------- /mu/resources/images/static.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/static.png -------------------------------------------------------------------------------- /mu/resources/images/step-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/step-in.png -------------------------------------------------------------------------------- /mu/resources/images/step-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/step-out.png -------------------------------------------------------------------------------- /mu/resources/images/step-over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/step-over.png -------------------------------------------------------------------------------- /mu/resources/images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/stop.png -------------------------------------------------------------------------------- /mu/resources/images/stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 57 | 64 | 71 | 78 | 79 | 81 | 82 | 84 | image/svg+xml 85 | 87 | 88 | 89 | 90 | 91 | 96 | 102 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /mu/resources/images/templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/templates.png -------------------------------------------------------------------------------- /mu/resources/images/theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/theme.png -------------------------------------------------------------------------------- /mu/resources/images/theme_contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/theme_contrast.png -------------------------------------------------------------------------------- /mu/resources/images/theme_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/theme_day.png -------------------------------------------------------------------------------- /mu/resources/images/theme_day.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 47 | 54 | 61 | 68 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 92 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /mu/resources/images/tidy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/tidy.png -------------------------------------------------------------------------------- /mu/resources/images/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/web.png -------------------------------------------------------------------------------- /mu/resources/images/zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/zoom-in.png -------------------------------------------------------------------------------- /mu/resources/images/zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/images/zoom-out.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/alien.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/alien_hurt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/alien_hurt.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/cat1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/cat1.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/cat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/cat2.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/cat3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/cat3.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/cat4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/cat4.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/eep.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/eep.wav -------------------------------------------------------------------------------- /mu/resources/pygamezero/meow1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/meow1.wav -------------------------------------------------------------------------------- /mu/resources/pygamezero/meow2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/meow2.wav -------------------------------------------------------------------------------- /mu/resources/pygamezero/meow3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/meow3.wav -------------------------------------------------------------------------------- /mu/resources/pygamezero/meow4.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/meow4.wav -------------------------------------------------------------------------------- /mu/resources/pygamezero/splat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/splat.png -------------------------------------------------------------------------------- /mu/resources/pygamezero/splat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/pygamezero/splat.wav -------------------------------------------------------------------------------- /mu/resources/web/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/mu/resources/web/static/img/logo.png -------------------------------------------------------------------------------- /mu/resources/web/templates/age.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 |

Age-o-meter

4 | 5 |

How old are you..? 6 | 7 |

8 | {% if error %} 9 |

{{error}}

10 | {% endif %} 11 | 12 | 13 | 14 |
15 | 16 | {% if days_old %} 17 |

Your are {{days_old}} days old.

18 | {% endif %} 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /mu/resources/web/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block title %}Hello from Mu! :-){% endblock %} 6 | 7 | 8 | 10 | 11 | 12 | 14 | 16 | 17 | 18 | 19 |
20 | {% block content %}{% endblock %} 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /mu/resources/web/templates/greeting.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 |

Hello!

4 |

Hello {{name}}, how are you?

5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /mu/resources/web/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 |
4 |
logo
5 |

Hello from Mu!

6 |
7 |
8 |

This is a very simple dynamic web application built using Python and 9 | the 10 | Flask web framework.

11 | 12 |

Why not try adding the following route to your Python code?

13 | 14 |

15 | @app.route('/hello/<name>')
16 | def greet(name='Stranger'):
17 |     return render_template("greeting.html", name=name)
18 |     
19 | 20 |

Now add the following template with the filename, "greeting.html".

21 |

22 | {% extends "base.html" %}
23 | {% block content %}
24 | <p>Hello {{name}}, how are you?</p>
25 | {% endblock %}
26 |     
27 | 28 |

Once you've done that, go visit 29 | /hello/yourname (but replace "yourname" in 30 | the address bar with, you know, your actual name). :-)

31 |
32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /mu/wheels/__main__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | 4 | from . import logger, download 5 | 6 | # 7 | # If run from the command line (eg python -m mu.wheels) 8 | # make sure all logging goes to stdout 9 | # 10 | logger.setLevel(logging.DEBUG) 11 | logger.addHandler(logging.StreamHandler()) 12 | 13 | # A single flag is accepted to trigger a `pip download` using flag to increase 14 | # compatibility with older operating system versions. 15 | # As there is a single option available sys.argv is used for simplicity, 16 | # if more options are added in the future we should start using argparse 17 | os_old_compat = sys.argv[1] == "--package" 18 | 19 | download(os_old_compat=os_old_compat) 20 | -------------------------------------------------------------------------------- /package/README.rst: -------------------------------------------------------------------------------- 1 | Packing Mu 2 | ========== 3 | 4 | Install dependencies 5 | -------------------- 6 | 7 | Windows 8 | +++++++ 9 | 10 | Please ensure you use the specified versions in the instructions below. We've 11 | found the latest versions of some of these packages are not always backwards 12 | compatible with each other. 13 | 14 | * Install the 32bit version of Python 3.4 from the `official website `_. 15 | * Install the PyQt5 binary package from `riverbankcomputing `_ (specifically, `this one `_). 16 | * Install PyInstaller using pip or pip3 (includes pypiwin32):: 17 | 18 | $ pip install pyinstaller==3.1.1 19 | 20 | If in doubt, look in the details of the ``appveyor.yml`` file in the root of 21 | this repository. 22 | 23 | Mac OS X 24 | ++++++++ 25 | 26 | Assuming you have the `Homebrew `_ package manager installed: 27 | 28 | * Install Python 3:: 29 | 30 | $ brew update 31 | $ brew install python3 32 | 33 | * Install the PyQt5 binary package:: 34 | 35 | $ pip3 install PyQt5 36 | 37 | * Install the QScintilla2 package using the formula in the `extras` directory:: 38 | 39 | $ pip3 install QScintilla 40 | 41 | * Install PyInstaller:: 42 | 43 | $ pip3 install pyinstaller 44 | 45 | Linux 46 | ----- 47 | 48 | Assuming you are running a Linux distribution with apt. 49 | 50 | * Install Python 3:: 51 | 52 | $ sudo apt-get update 53 | $ sudo apt-get install python3 54 | 55 | * Install PyQt5:: 56 | 57 | $ sudo apt-get install python3-pyqt5 python3-pyqt5.qsci python3-pyqt5.qtserialport 58 | 59 | * Install PyInstaller:: 60 | 61 | $ pip3 install pyinstaller 62 | 63 | 64 | Package Mu 65 | ---------- 66 | 67 | From the project root directory, run:: 68 | 69 | $ pyinstaller package/pyinstaller.spec 70 | 71 | The single file executable should be saved in `/dist/mu`, `/dist/mu.exe`, or `/dist/mu.app`. 72 | 73 | The spec file `package/pyinstaller.spec` can be edited to simplify packaging debugging. 74 | 75 | 76 | Run the executable 77 | ------------------ 78 | 79 | On Windows you can simply double-click the `mu.exe` file. 80 | 81 | On Linux ensure the file permissions are set to executable and, from the file location, run:: 82 | 83 | $ ./mu 84 | 85 | On OS X double click on the `mu.app`, if trying to run the downloadable version, right click on the file and select `open`. 86 | 87 | 88 | Download the Mu executable 89 | -------------------------- 90 | 91 | .. image:: https://ci.appveyor.com/api/projects/status/agr9wmestx3t1tcl/branch/master?svg=true 92 | :target: https://ci.appveyor.com/project/carlosperate/mu 93 | 94 | .. image:: https://travis-ci.org/mu-editor/mu.svg?branch=master 95 | :target: https://travis-ci.org/mu-editor/mu 96 | 97 | You can download the latest executable build of Mu for your respective operating system from the following links: 98 | 99 | * `Windows `_ 100 | * `Mac OS X `_ 101 | * `Linux `_ 102 | -------------------------------------------------------------------------------- /package/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/package/__init__.py -------------------------------------------------------------------------------- /package/icons/mac_icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/package/icons/mac_icon.icns -------------------------------------------------------------------------------- /package/icons/win_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/package/icons/win_icon.ico -------------------------------------------------------------------------------- /package/install_pip3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ev 3 | # Check python3 installation 4 | python3 --version 5 | python3 -c "import sys; print(sys.executable)" 6 | # Install pip 7 | curl -O https://bootstrap.pypa.io/get-pip.py 8 | python3 get-pip.py 9 | rm get-pip.py 10 | -------------------------------------------------------------------------------- /package/qt.conf: -------------------------------------------------------------------------------- 1 | [Paths] 2 | Prefix = PyQt5/Qt 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Mu doesn't use requirements.txt: 2 | # - To install please refer to https://codewith.mu/. 3 | # - To setup a development environment see https://mu.readthedocs.io/. 4 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from mu.app import run 3 | 4 | 5 | if __name__ == "__main__": 6 | run() 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | # see http://pycodestyle.pycqa.org/en/latest/intro.html#error-codes 3 | ignore = 4 | # whitespace before ':' 5 | # Ignored because of https://github.com/PyCQA/pycodestyle/issues/373 6 | E203 7 | # do not assign a lambda expression, use a def 8 | E731 9 | # module level import not at top of file 10 | E402 11 | # line break occurred before a binary operator 12 | W503 13 | # line break after binary operator 14 | W504 15 | exclude = 16 | ./docs/ 17 | ./mu/contrib/ 18 | ./mu/modes/api/ 19 | ./package/ 20 | ./utils/ 21 | # Common names for virtual environment directories. 22 | ./venv/ 23 | ./.venv*/ 24 | ./env/ 25 | ./.env/ 26 | ./local-scripts/ 27 | max-line-length = 88 28 | 29 | [coverage:run] 30 | omit = mu/contrib/*, mu/mu_debug.py, mu/__main__.py, mu/wheels/* 31 | 32 | [tool:pytest] 33 | filterwarnings = ignore::DeprecationWarning 34 | addopts = --random-order 35 | -------------------------------------------------------------------------------- /tests/README.rst: -------------------------------------------------------------------------------- 1 | Mu Tests 2 | ======== 3 | 4 | We aim for 100% test coverage - it means someone has expressed an opinion about 5 | how all the code paths for the application should behave. THIS DOES NOT MEAN 6 | THE CODE IS BUG FREE! 7 | 8 | The tests are organised to mirror the structure of the application itself. 9 | 10 | To run the test suite, ensure you're in the *root* directory of the repository 11 | and run the following command:: 12 | 13 | $ make check 14 | 15 | This will run the code style analysis, code quality analysis, test suite and 16 | coverage check. To just run each of these use the following commands: 17 | 18 | * Coding style:: 19 | 20 | $ make pep8 21 | 22 | * Code quality:: 23 | 24 | $ make pyflakes 25 | 26 | * Test suite only:: 27 | 28 | $ make test 29 | 30 | * Code coverage:: 31 | 32 | $ make coverage 33 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | from unittest import mock 2 | 3 | import pytest 4 | import os 5 | import random 6 | from PyQt5.QtWidgets import QApplication 7 | 8 | from mu import settings 9 | 10 | # Keep global reference to avoid being garbage collected 11 | _qapp_instance = None 12 | 13 | 14 | @pytest.fixture(scope="session", autouse=True) 15 | def qtapp(): 16 | app = QApplication.instance() 17 | if app is None: 18 | global _qapp_instance 19 | _qapp_instance = QApplication([]) 20 | return _qapp_instance 21 | else: 22 | return app 23 | 24 | 25 | @pytest.fixture(scope="session", autouse=True) 26 | def disable_autosave(): 27 | """Ensure that no settings are autosaved as part of a test""" 28 | with mock.patch.object( 29 | settings.SettingsBase, "register_for_autosave" 30 | ) as register: 31 | yield register 32 | 33 | 34 | @pytest.fixture(autouse=True) 35 | def temp_shared_mem_app_name(): 36 | """Make multi-instance execution blocking shared memory app name unique for tests""" 37 | os.environ["MU_TEST_SUPPORT_RANDOM_APP_NAME_EXT"] = "_" + str( 38 | random.randint(0, 100000000) 39 | ) 40 | yield 41 | os.environ.pop("MU_TEST_SUPPORT_RANDOM_APP_NAME_EXT", "") 42 | -------------------------------------------------------------------------------- /tests/customhextest.hex: -------------------------------------------------------------------------------- 1 | hexcontentstest -------------------------------------------------------------------------------- /tests/debugger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/tests/debugger/__init__.py -------------------------------------------------------------------------------- /tests/debugger/test_utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Tests for the debug utils. 4 | """ 5 | from mu.debugger.utils import is_breakpoint_line 6 | 7 | 8 | def test_is_breakpoint_line_valid_code(): 9 | """ 10 | A simple check to ensure a valid line of Python returns True. 11 | """ 12 | code = 'print("Hello")' 13 | assert is_breakpoint_line(code) 14 | 15 | 16 | def test_is_breakpoint_line_valid_code_with_whitespace(): 17 | """ 18 | If the line of code is indented with whitespace, ensure it returns True. 19 | """ 20 | code = ' print("Hello")' 21 | assert is_breakpoint_line(code) 22 | 23 | 24 | def test_is_breakpoint_line_valid_blank_line(): 25 | """ 26 | If the line is blank, you can't set a breakpoint. 27 | """ 28 | assert is_breakpoint_line(" ") is False 29 | 30 | 31 | def test_is_breakpoint_line_comment(): 32 | """ 33 | You can't set a breakpoint on a line that is a comment. 34 | """ 35 | assert is_breakpoint_line("# A comment") is False 36 | assert is_breakpoint_line('""" A comment """') is False 37 | assert is_breakpoint_line("''' A comment'''") is False 38 | 39 | 40 | def test_is_breakpoint_line_opening_collection(): 41 | """ 42 | It's common to write things like: 43 | 44 | foo = [ 45 | 'a', 46 | 'b', 47 | 'c', 48 | ] 49 | 50 | Breakpoints cannot be set on the first line of this statement (for all 51 | collection types). 52 | """ 53 | assert is_breakpoint_line("foo = [") is False 54 | assert is_breakpoint_line("foo = {") is False 55 | assert is_breakpoint_line("foo = (") is False 56 | 57 | 58 | def test_is_breakpoint_line_closing_collection(): 59 | """ 60 | It's common to write things like: 61 | 62 | foo = [ 63 | 'a', 64 | 'b', 65 | 'c', 66 | ] 67 | 68 | Breakpoints cannot be set on the final line of this statement (for all 69 | collection types). 70 | """ 71 | assert is_breakpoint_line("]") is False 72 | assert is_breakpoint_line("}") is False 73 | assert is_breakpoint_line(")") is False 74 | -------------------------------------------------------------------------------- /tests/interface/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/tests/interface/__init__.py -------------------------------------------------------------------------------- /tests/interface/test_themes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Tests for the user interface elements of Mu. 4 | """ 5 | from unittest import mock 6 | import mu.interface.themes 7 | import mu.interface.editor 8 | 9 | 10 | def test_constants(): 11 | """ 12 | Ensure the expected constant values exist. 13 | """ 14 | assert mu.interface.themes.NIGHT_STYLE 15 | assert mu.interface.themes.DAY_STYLE 16 | 17 | 18 | def test_Font(): 19 | """ 20 | Ensure the Font class works as expected with default and passed in args. 21 | """ 22 | f = mu.interface.themes.Font() 23 | # Defaults 24 | assert f.color == "#181818" 25 | assert f.paper == "#FEFEF7" 26 | assert f.bold is False 27 | assert f.italic is False 28 | # Passed in arguments 29 | f = mu.interface.themes.Font( 30 | color="pink", paper="black", bold=True, italic=True 31 | ) 32 | assert f.color == "pink" 33 | assert f.paper == "black" 34 | assert f.bold 35 | assert f.italic 36 | 37 | 38 | def test_theme_apply_to(): 39 | """ 40 | Ensure that the apply_to class method updates the passed in lexer with the 41 | expected font settings. 42 | """ 43 | lexer = mu.interface.editor.PythonLexer() 44 | theme = mu.interface.themes.DayTheme() 45 | lexer.setFont = mock.MagicMock(return_value=None) 46 | lexer.setColor = mock.MagicMock(return_value=None) 47 | lexer.setEolFill = mock.MagicMock(return_value=None) 48 | lexer.setPaper = mock.MagicMock(return_value=None) 49 | theme.apply_to(lexer) 50 | fstrings = 4 if hasattr(lexer, "DoubleQuotedFString") else 0 51 | assert lexer.setFont.call_count == 17 + fstrings 52 | assert lexer.setColor.call_count == 16 + fstrings 53 | assert lexer.setEolFill.call_count == 16 + fstrings 54 | assert lexer.setPaper.call_count == 16 + fstrings 55 | 56 | 57 | def test_Font_loading(): 58 | mu.interface.themes.Font._DATABASE = None 59 | try: 60 | with mock.patch("mu.interface.themes.QFontDatabase") as db: 61 | mu.interface.themes.Font().load() 62 | mu.interface.themes.Font(bold=True).load() 63 | mu.interface.themes.Font(italic=True).load() 64 | mu.interface.themes.Font(bold=True, italic=True).load() 65 | finally: 66 | mu.interface.themes.Font._DATABASE = None 67 | db.assert_called_once_with() 68 | db().font.assert_has_calls( 69 | [ 70 | mock.call("Source Code Pro", "Regular", 14), 71 | mock.call("Source Code Pro", "Semibold", 14), 72 | mock.call("Source Code Pro", "Italic", 14), 73 | mock.call("Source Code Pro", "Semibold Italic", 14), 74 | ] 75 | ) 76 | -------------------------------------------------------------------------------- /tests/modes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/tests/modes/__init__.py -------------------------------------------------------------------------------- /tests/modes/chromeos_devpath_exists.txt: -------------------------------------------------------------------------------- 1 | /mnt/chromeos/removable/CIRCUITPY -------------------------------------------------------------------------------- /tests/modes/chromeos_devpath_missing.txt: -------------------------------------------------------------------------------- 1 | /mnt/chromeos/removable -------------------------------------------------------------------------------- /tests/modes/mount_exists.txt: -------------------------------------------------------------------------------- 1 | sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) 2 | proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) 3 | udev on /dev type devtmpfs (rw,relatime,size=10240k,nr_inodes=489849,mode=755) 4 | devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000) 5 | tmpfs on /run type tmpfs (rw,nosuid,relatime,size=787732k,mode=755) 6 | /dev/mapper/heraclitus--vg-root on / type ext4 (rw,relatime,errors=remount-ro,data=ordered) 7 | /dev/sdb on /media/ntoll/CIRCUITPY type vfat (rw,nosuid,nodev,relatime,uid=1000,gid=1000,fmask=0022,dmask=0077,codepage=437,iocharset=utf8,shortname=mixed,showexec,utf8,flush,errors=remount-ro,uhelper=udisks2) 8 | /dev/sdc1 on /media/PYBFLASH type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro) 9 | -------------------------------------------------------------------------------- /tests/modes/mount_missing.txt: -------------------------------------------------------------------------------- 1 | sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) 2 | proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) 3 | udev on /dev type devtmpfs (rw,relatime,size=10240k,nr_inodes=489849,mode=755) 4 | devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000) 5 | tmpfs on /run type tmpfs (rw,nosuid,relatime,size=787732k,mode=755) 6 | /dev/mapper/heraclitus--vg-root on / type ext4 (rw,relatime,errors=remount-ro,data=ordered) 7 | -------------------------------------------------------------------------------- /tests/modes/test_lego.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the minimalist Lego Spike mode. 3 | """ 4 | import pytest 5 | from unittest import mock 6 | from mu.modes.lego import LegoMode 7 | from mu.modes.api import LEGO_APIS, SHARED_APIS 8 | 9 | 10 | @pytest.fixture 11 | def lego_mode(): 12 | editor = mock.MagicMock() 13 | view = mock.MagicMock() 14 | lego_mode = LegoMode(editor, view) 15 | return lego_mode 16 | 17 | 18 | def test_api(lego_mode): 19 | """ 20 | Ensure the right thing comes back from the API. 21 | """ 22 | api = lego_mode.api() 23 | assert api == SHARED_APIS + LEGO_APIS 24 | -------------------------------------------------------------------------------- /tests/modes/test_pico.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the minimalist Pico mode. 3 | """ 4 | import pytest 5 | from unittest import mock 6 | from mu.modes.pico import PicoMode 7 | from mu.modes.api import SHARED_APIS 8 | 9 | 10 | @pytest.fixture 11 | def pico_mode(): 12 | editor = mock.MagicMock() 13 | view = mock.MagicMock() 14 | pico_mode = PicoMode(editor, view) 15 | return pico_mode 16 | 17 | 18 | def test_api(pico_mode): 19 | """ 20 | Ensure the right thing comes back from the API. 21 | """ 22 | api = pico_mode.api() 23 | assert api == SHARED_APIS 24 | -------------------------------------------------------------------------------- /tests/scripts/.gitignore: -------------------------------------------------------------------------------- 1 | *.json -------------------------------------------------------------------------------- /tests/scripts/contains_blue.py: -------------------------------------------------------------------------------- 1 | blue = "blue" 2 | -------------------------------------------------------------------------------- /tests/scripts/contains_brown.py: -------------------------------------------------------------------------------- 1 | brown = "brown" 2 | -------------------------------------------------------------------------------- /tests/scripts/contains_green.py: -------------------------------------------------------------------------------- 1 | green = "green" 2 | -------------------------------------------------------------------------------- /tests/scripts/contains_red.py: -------------------------------------------------------------------------------- 1 | red = "red" 2 | -------------------------------------------------------------------------------- /tests/scripts/pycodestyle: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore = E265 3 | -------------------------------------------------------------------------------- /tests/session.json: -------------------------------------------------------------------------------- 1 | {"theme": "night", "paths": ["path/foo.py", "path/bar.py"], "mode": "python"} 2 | -------------------------------------------------------------------------------- /tests/settings.json: -------------------------------------------------------------------------------- 1 | {"theme": "night", "paths": ["path/foo.py", "path/bar.py"], "workspace": "/home/foo/mycode", "mode": "python", "microbit_runtime_hex": null} 2 | -------------------------------------------------------------------------------- /tests/settingscorrupt.json: -------------------------------------------------------------------------------- 1 | GARBAGE 2 | -------------------------------------------------------------------------------- /tests/settingswithcustomhex.json: -------------------------------------------------------------------------------- 1 | {"theme": "night", "paths": ["path/foo.py", "path/bar.py"], "workspace": "/home/foo/mycode", "microbit_runtime_hex": "customhextest.hex"} 2 | -------------------------------------------------------------------------------- /tests/settingswithmissingcustomhex.json: -------------------------------------------------------------------------------- 1 | {"theme": "night", "paths": ["path/foo.py", "path/bar.py"], "workspace": "/home/foo/mycode", "microbit_runtime_hex": "customhextest-missing.hex"} 2 | -------------------------------------------------------------------------------- /tests/settingswithoutworkspace.json: -------------------------------------------------------------------------------- 1 | {"theme": "night", "paths": ["path/foo.py", "path/bar.py"]} 2 | -------------------------------------------------------------------------------- /tests/test_resources.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Tests for the resources sub-module. 4 | """ 5 | import mu.resources 6 | from unittest import mock 7 | from PyQt5.QtGui import QIcon, QPixmap, QMovie 8 | 9 | 10 | def test_path(): 11 | """ 12 | Ensure the resource_filename function is called with the expected args and 13 | the path function under test returns its result. 14 | """ 15 | with mock.patch("mu.resources.resource_filename", return_value="bar") as r: 16 | assert mu.resources.path("foo") == "bar" 17 | r.assert_called_once_with(mu.resources.__name__, "images/foo") 18 | 19 | 20 | def test_load_icon(): 21 | """ 22 | Check the load_icon function returns the expected QIcon object. 23 | """ 24 | result = mu.resources.load_icon("icon") 25 | assert isinstance(result, QIcon) 26 | 27 | 28 | def test_load_pixmap(): 29 | """ 30 | Check the load_pixmap function returns the expected QPixmap object. 31 | """ 32 | result = mu.resources.load_pixmap("icon") 33 | assert isinstance(result, QPixmap) 34 | 35 | 36 | def test_load_movie(): 37 | """ 38 | Check the load_movie function returns the expected QMovie object. 39 | """ 40 | result = mu.resources.load_movie("splash_screen") 41 | assert isinstance(result, QMovie) 42 | 43 | 44 | def test_stylesheet(): 45 | """ 46 | Ensure the resource_string function is called with the expected args and 47 | the load_stylesheet function returns its result. 48 | """ 49 | with mock.patch("mu.resources.resource_string", return_value=b"foo") as rs: 50 | assert "foo" == mu.resources.load_stylesheet("foo") 51 | rs.assert_called_once_with(mu.resources.__name__, "css/foo") 52 | 53 | 54 | def test_load_font_data(): 55 | """ 56 | Ensure font data can be loaded 57 | """ 58 | with mock.patch("mu.resources.resource_string", return_value=b"foo") as rs: 59 | assert b"foo" == mu.resources.load_font_data("foo") 60 | rs.assert_called_once_with(mu.resources.__name__, "fonts/foo") 61 | -------------------------------------------------------------------------------- /tests/virtual_environment/wheels/arrr-1.0.2-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/tests/virtual_environment/wheels/arrr-1.0.2-py3-none-any.whl -------------------------------------------------------------------------------- /tests/virtual_environment/wheels/wheels.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mu-editor/mu/563cb860c83b9453fc901d80dfb9ef8ed49503fc/tests/virtual_environment/wheels/wheels.zip -------------------------------------------------------------------------------- /utils/README.rst: -------------------------------------------------------------------------------- 1 | Utilities 2 | ========= 3 | 4 | This directory contains utilities used to help maintain Mu. For example, 5 | scripts used to extract API documentation for use in Mu's auto-suggest and 6 | tool tips. 7 | -------------------------------------------------------------------------------- /utils/avatar.py: -------------------------------------------------------------------------------- 1 | # Grab Gravatar images for the contributors listed in the GIT log. 2 | import os 3 | import subprocess 4 | import shutil 5 | import hashlib 6 | import requests 7 | 8 | 9 | def get_gravatar(email): 10 | """ 11 | Given an email, attempt to get the gravatar image associated with it. 12 | """ 13 | md5 = hashlib.md5(email.encode("utf-8")).hexdigest() 14 | url = f"http://www.gravatar.com/avatar/{md5}?d=404&size=90" 15 | return requests.get(url, stream=True) 16 | 17 | 18 | def get_github(username): 19 | """ 20 | Given a GitHub username, attempt to get the user's avatar. 21 | """ 22 | url = f"https://github.com/{username}.png" 23 | return requests.get(url, stream=True) 24 | 25 | 26 | def get_gitlog(): 27 | """ 28 | Get unique tuples of username / email address from GIT log. 29 | """ 30 | command = ["git", "log", "--pretty=format:%an|%ae"] 31 | raw = subprocess.check_output(command, stderr=subprocess.STDOUT).decode( 32 | "utf-8" 33 | ) 34 | lines = raw.split("\n") 35 | result = set() 36 | for line in lines: 37 | username, email = line.split("|") 38 | result.add((username, email)) 39 | return tuple(result) 40 | 41 | 42 | users = get_gitlog() 43 | path = os.path.abspath(os.path.join(".git", "avatar")) 44 | if not os.path.exists(path): 45 | os.makedirs(path) 46 | 47 | for (username, email) in users: 48 | print(f"Processing {username} {email}") 49 | if "users.noreply.github.com" in email: 50 | raw_username, _ = email.split("@") 51 | response = get_github(raw_username) 52 | _, mime = response.headers["content-type"].split("/") 53 | else: 54 | response = get_gravatar(email) 55 | _, mime = response.headers["content-type"].split("/") 56 | if response.status_code == 200: 57 | filename = os.path.join(path, f"{username}.{mime}") 58 | with open(filename, "wb") as out_file: 59 | print(f"Writing to {filename}") 60 | shutil.copyfileobj(response.raw, out_file) 61 | -------------------------------------------------------------------------------- /utils/gh_downloads.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Retrieves the GH releases stats from their open API and counts the total number 4 | of asset downloads, which so far are all Mu installers. 5 | """ 6 | import datetime 7 | import requests 8 | 9 | 10 | releases = requests.get( 11 | "https://api.github.com/repos/mu-editor/mu/releases" 12 | ).json() 13 | 14 | # First generate date objects for each release and add them to their dictionary 15 | for release in releases: 16 | date_str = release["published_at"].split("T")[0] 17 | release["date_processed"] = datetime.date.fromisoformat(date_str) 18 | 19 | total_downloads = 0 20 | 21 | # Print the release info in reverse order, old to new 22 | reversed_releases = releases[::-1] 23 | for i, release in enumerate(reversed_releases): 24 | if i < (len(reversed_releases) - 1): 25 | next_date = reversed_releases[i + 1]["date_processed"] 26 | else: 27 | next_date = datetime.date.today() 28 | diff_date = next_date - release["date_processed"] 29 | months_days_diff = divmod(diff_date.days, 30) 30 | print( 31 | "\nRelease {} ({}, {} months and {} days):".format( 32 | release["tag_name"], 33 | release["date_processed"], 34 | months_days_diff[0], 35 | months_days_diff[1], 36 | ) 37 | ) 38 | 39 | if "assets" in release and len(release["assets"]): 40 | for asset in release["assets"]: 41 | total_downloads += asset["download_count"] 42 | print( 43 | "\tDownloads: {:6}".format(asset["download_count"]), end="\t" 44 | ) 45 | print("Asset: {}".format(asset["name"])) 46 | else: 47 | print("\tNo assets on this release") 48 | 49 | print("\nTotal Mu Editor asset downloads: {} 🎉".format(total_downloads)) 50 | -------------------------------------------------------------------------------- /utils/mkapi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Takes a JSON representation of an API and emits elements to be inserted into a 4 | Python list such that they conform to Scintilla's API description DSL. 5 | """ 6 | import sys 7 | import json 8 | 9 | 10 | if __name__ == "__main__": 11 | f = sys.argv[1] 12 | with open(f) as api_file: 13 | api = json.load(api_file) 14 | # Sort the JSON objects so diffing code is easier to do. 15 | sorted_api = sorted(api, key=lambda k: k["name"]) 16 | # Emit a representation of the API information in the format parsed by 17 | # the Scintilla. 18 | for i in sorted_api: 19 | name = i["name"] 20 | args = ", ".join(i["args"]) if i["args"] else "" 21 | description = i["description"].replace("\u2013", "--") 22 | content = repr("{}({}) \n{}".format(name, args, description)) 23 | print(" _({}),".format(content)) 24 | -------------------------------------------------------------------------------- /utils/pgzero_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Given a list of modules, extracts the help into a json file to be turned into 4 | an API list for Mu. 5 | """ 6 | import json 7 | import inspect 8 | import importlib 9 | 10 | 11 | modules = ["screen", "music", "keyboard", "clock", "animation", "actor"] 12 | 13 | api = [] 14 | 15 | for module in modules: 16 | m = importlib.import_module("pgzero.{}".format(module)) 17 | content = [attr for attr in dir(m) if not attr.startswith("_")] 18 | # Work out what each member of the module is. 19 | for attr in content: 20 | obj = getattr(m, attr) 21 | name = "" 22 | try: 23 | name = obj.__name__ 24 | except Exception as ex: 25 | print(obj) 26 | print(ex) 27 | try: 28 | args = [ 29 | a.replace("(", "").replace(")", "") 30 | for a in str(inspect.signature(obj)).split(", ") 31 | ] 32 | except Exception as ex: 33 | print(obj) 34 | print(ex) 35 | args = None 36 | description = inspect.getdoc(obj) 37 | if name and description: 38 | api.append( 39 | { 40 | "name": module + "." + name, 41 | "args": args, 42 | "description": description, 43 | } 44 | ) 45 | 46 | 47 | with open("pgzero_api.json", "w") as output: 48 | json.dump(api, output, indent=2) 49 | -------------------------------------------------------------------------------- /utils/python3_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Given a list of modules, extracts the help into a json file to be turned into 4 | an API list for Mu. 5 | """ 6 | import json 7 | import inspect 8 | import importlib 9 | 10 | 11 | modules = [ 12 | "random", 13 | "sys", 14 | "os", 15 | "json", 16 | "socket", 17 | "datetime", 18 | "collections", 19 | "datetime", 20 | "array", 21 | "itertools", 22 | "functools", 23 | "os.path", 24 | "csv", 25 | "time", 26 | "argparse", 27 | "base64", 28 | "hashlib", 29 | "uuid", 30 | "turtle", 31 | ] 32 | 33 | api = [] 34 | 35 | for module in modules: 36 | m = importlib.import_module(module) 37 | content = [attr for attr in dir(m) if not attr.startswith("_")] 38 | # Work out what each member of the module is. 39 | for attr in content: 40 | obj = getattr(m, attr) 41 | name = "" 42 | try: 43 | name = obj.__name__ 44 | except Exception as ex: 45 | print(ex) 46 | print(obj) 47 | try: 48 | args = [ 49 | a.replace("(", "").replace(")", "") 50 | for a in str(inspect.signature(obj)).split(", ") 51 | ] 52 | except Exception as ex: 53 | print(ex) 54 | print(obj) 55 | args = None 56 | description = inspect.getdoc(obj) 57 | if name and description: 58 | api.append( 59 | { 60 | "name": module + "." + name, 61 | "args": args, 62 | "description": description, 63 | } 64 | ) 65 | 66 | 67 | with open("python_api.json", "w") as output: 68 | json.dump(api, output, indent=2) 69 | --------------------------------------------------------------------------------