├── .gitattributes ├── .github └── workflows │ └── python-package.yml ├── .gitignore ├── LICENSE ├── README.md ├── VERSION ├── docs ├── Makefile ├── build │ ├── doctrees │ │ ├── environment.pickle │ │ ├── index.doctree │ │ ├── modules.doctree │ │ ├── puremvc.core.doctree │ │ ├── puremvc.doctree │ │ ├── puremvc.interfaces.doctree │ │ ├── puremvc.patterns.command.doctree │ │ ├── puremvc.patterns.doctree │ │ ├── puremvc.patterns.facade.doctree │ │ ├── puremvc.patterns.mediator.doctree │ │ ├── puremvc.patterns.observer.doctree │ │ └── puremvc.patterns.proxy.doctree │ └── html │ │ ├── .buildinfo │ │ ├── _sources │ │ ├── index.rst.txt │ │ ├── modules.rst.txt │ │ ├── puremvc.core.rst.txt │ │ ├── puremvc.interfaces.rst.txt │ │ ├── puremvc.patterns.command.rst.txt │ │ ├── puremvc.patterns.facade.rst.txt │ │ ├── puremvc.patterns.mediator.rst.txt │ │ ├── puremvc.patterns.observer.rst.txt │ │ ├── puremvc.patterns.proxy.rst.txt │ │ ├── puremvc.patterns.rst.txt │ │ └── puremvc.rst.txt │ │ ├── _static │ │ ├── _sphinx_javascript_frameworks_compat.js │ │ ├── basic.css │ │ ├── css │ │ │ ├── badge_only.css │ │ │ ├── fonts │ │ │ │ ├── Roboto-Slab-Bold.woff │ │ │ │ ├── Roboto-Slab-Bold.woff2 │ │ │ │ ├── Roboto-Slab-Regular.woff │ │ │ │ ├── Roboto-Slab-Regular.woff2 │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ ├── fontawesome-webfont.woff2 │ │ │ │ ├── lato-bold-italic.woff │ │ │ │ ├── lato-bold-italic.woff2 │ │ │ │ ├── lato-bold.woff │ │ │ │ ├── lato-bold.woff2 │ │ │ │ ├── lato-normal-italic.woff │ │ │ │ ├── lato-normal-italic.woff2 │ │ │ │ ├── lato-normal.woff │ │ │ │ └── lato-normal.woff2 │ │ │ └── theme.css │ │ ├── doctools.js │ │ ├── documentation_options.js │ │ ├── file.png │ │ ├── fonts │ │ │ ├── Lato │ │ │ │ ├── lato-bold.eot │ │ │ │ ├── lato-bold.ttf │ │ │ │ ├── lato-bold.woff │ │ │ │ ├── lato-bold.woff2 │ │ │ │ ├── lato-bolditalic.eot │ │ │ │ ├── lato-bolditalic.ttf │ │ │ │ ├── lato-bolditalic.woff │ │ │ │ ├── lato-bolditalic.woff2 │ │ │ │ ├── lato-italic.eot │ │ │ │ ├── lato-italic.ttf │ │ │ │ ├── lato-italic.woff │ │ │ │ ├── lato-italic.woff2 │ │ │ │ ├── lato-regular.eot │ │ │ │ ├── lato-regular.ttf │ │ │ │ ├── lato-regular.woff │ │ │ │ └── lato-regular.woff2 │ │ │ └── RobotoSlab │ │ │ │ ├── roboto-slab-v7-bold.eot │ │ │ │ ├── roboto-slab-v7-bold.ttf │ │ │ │ ├── roboto-slab-v7-bold.woff │ │ │ │ ├── roboto-slab-v7-bold.woff2 │ │ │ │ ├── roboto-slab-v7-regular.eot │ │ │ │ ├── roboto-slab-v7-regular.ttf │ │ │ │ ├── roboto-slab-v7-regular.woff │ │ │ │ └── roboto-slab-v7-regular.woff2 │ │ ├── jquery-3.6.0.js │ │ ├── jquery.js │ │ ├── js │ │ │ ├── badge_only.js │ │ │ ├── html5shiv-printshiv.min.js │ │ │ ├── html5shiv.min.js │ │ │ ├── theme.js │ │ │ └── versions.js │ │ ├── language_data.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ ├── sphinx_highlight.js │ │ ├── underscore-1.13.1.js │ │ └── underscore.js │ │ ├── genindex.html │ │ ├── index.html │ │ ├── modules.html │ │ ├── objects.inv │ │ ├── puremvc.core.html │ │ ├── puremvc.html │ │ ├── puremvc.interfaces.html │ │ ├── puremvc.patterns.command.html │ │ ├── puremvc.patterns.facade.html │ │ ├── puremvc.patterns.html │ │ ├── puremvc.patterns.mediator.html │ │ ├── puremvc.patterns.observer.html │ │ ├── puremvc.patterns.proxy.html │ │ ├── py-modindex.html │ │ ├── search.html │ │ └── searchindex.js ├── make.bat └── source │ ├── conf.py │ ├── index.rst │ ├── modules.rst │ ├── puremvc.core.rst │ ├── puremvc.interfaces.rst │ ├── puremvc.patterns.command.rst │ ├── puremvc.patterns.facade.rst │ ├── puremvc.patterns.mediator.rst │ ├── puremvc.patterns.observer.rst │ ├── puremvc.patterns.proxy.rst │ ├── puremvc.patterns.rst │ └── puremvc.rst ├── pyproject.toml ├── src └── puremvc │ ├── __init__.py │ ├── core │ ├── Controller.py │ ├── Model.py │ ├── View.py │ └── __init__.py │ ├── interfaces │ ├── ICommand.py │ ├── IController.py │ ├── IFacade.py │ ├── IMediator.py │ ├── IModel.py │ ├── INotification.py │ ├── INotifier.py │ ├── IObserver.py │ ├── IProxy.py │ ├── IView.py │ └── __init__.py │ └── patterns │ ├── __init__.py │ ├── command │ ├── MacroCommand.py │ ├── SimpleCommand.py │ └── __init__.py │ ├── facade │ ├── Facade.py │ ├── Notifier.py │ └── __init__.py │ ├── mediator │ ├── Mediator.py │ └── __init__.py │ ├── observer │ ├── Notification.py │ ├── Observer.py │ └── __init__.py │ └── proxy │ ├── Proxy.py │ └── __init__.py └── test ├── core ├── Controller_test.py ├── Model_test.py └── View_test.py └── patterns ├── __init__.py ├── command ├── MacroCommand_test.py └── SimpleCommand_test.py ├── facade └── Facade_test.py ├── mediator └── Mediator_test.py ├── observer ├── Notification_test.py ├── Notifier_test.py └── Observer_test.py └── proxy └── Proxy_test.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Detect Python code only from these folders 2 | src/** linguist-detectable=true 3 | test/** linguist-detectable=true 4 | 5 | # Ignore documentation and build artifacts in language stats 6 | docs/** linguist-detectable=false 7 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: [ "3.10", "3.11", "3.12" ] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v3 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install flake8 pytest 31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | - name: Install package in editable mode 39 | run: pip install -e . 40 | - name: Test with pytest 41 | run: | 42 | pytest test/ 43 | -------------------------------------------------------------------------------- /.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 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | share/python-wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | *.py,cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | cover/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | db.sqlite3-journal 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | .pybuilder/ 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | # For a library or package, you might want to ignore these files since the code is 86 | # intended to run in multiple environments; otherwise, check them in: 87 | # .python-version 88 | 89 | # pipenv 90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 93 | # install all needed dependencies. 94 | #Pipfile.lock 95 | 96 | # poetry 97 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 98 | # This is especially recommended for binary packages to ensure reproducibility, and is more 99 | # commonly ignored for libraries. 100 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 101 | #poetry.lock 102 | 103 | # pdm 104 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 105 | #pdm.lock 106 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 107 | # in version control. 108 | # https://pdm.fming.dev/#use-with-ide 109 | .pdm.toml 110 | 111 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 112 | __pypackages__/ 113 | 114 | # Celery stuff 115 | celerybeat-schedule 116 | celerybeat.pid 117 | 118 | # SageMath parsed files 119 | *.sage.py 120 | 121 | # Environments 122 | .env 123 | .venv 124 | env/ 125 | venv/ 126 | ENV/ 127 | env.bak/ 128 | venv.bak/ 129 | 130 | # Spyder project settings 131 | .spyderproject 132 | .spyproject 133 | 134 | # Rope project settings 135 | .ropeproject 136 | 137 | # mkdocs documentation 138 | /site 139 | 140 | # mypy 141 | .mypy_cache/ 142 | .dmypy.json 143 | dmypy.json 144 | 145 | # Pyre type checker 146 | .pyre/ 147 | 148 | # pytype static type analyzer 149 | .pytype/ 150 | 151 | # Cython debug symbols 152 | cython_debug/ 153 | 154 | # PyCharm 155 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 156 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 157 | # and can be added to the global gitignore or merged into this file. For a more nuclear 158 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 159 | #.idea/ 160 | 161 | .DS_Store 162 | .idea 163 | __pycache__ 164 | src/PureMVC.egg-info -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | * PureMVC MultiCore Framework for Python - Copyright © 2025 Saad Shams 4 | * PureMVC - Copyright © 2025 Futurescale, Inc. 5 | * All rights reserved. 6 | 7 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | * Neither the name of Futurescale, Inc., PureMVC.org, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [PureMVC](http://puremvc.github.com/) Python MultiCore Framework [![Python package](https://github.com/PureMVC/puremvc-python-multicore-framework/actions/workflows/python-package.yml/badge.svg)](https://github.com/PureMVC/puremvc-python-multicore-framework/actions/workflows/python-package.yml) 2 | 3 | PureMVC is a lightweight framework for creating applications based upon the classic [Model-View-Controller](http://en.wikipedia.org/wiki/Model-view-controller) design meta-pattern. It supports [modular programming](http://en.wikipedia.org/wiki/Modular_programming) through the use of [Multiton](http://en.wikipedia.org/wiki/Multiton) Core actors instead of the [Singleton](http://en.wikipedia.org/wiki/Singleton_pattern)s used in the [Standard Version](https://github.com/PureMVC/puremvc-python-standard-framework/wiki). 4 | 5 | * [PyPI Package](https://pypi.org/project/PureMVC/) 6 | * [API Docs](https://puremvc.org/pages/docs/Python/multicore) 7 | * [Legacy Implementation](https://github.com/PureMVC/puremvc-python-multicore-framework/tree/1.0.1) 8 | 9 | # Installation 10 | 11 | ```commandline 12 | pip install PureMVC 13 | ``` 14 | --- 15 | 16 | ## Development 17 | 18 | ### Install Dependency (Editable Package) 19 | ```shell 20 | pip install -e . 21 | ``` 22 | 23 | ### Type Checking 24 | ```shell 25 | pip install mypy 26 | mypy ./src 27 | ``` 28 | 29 | ### Testing 30 | ```shell 31 | pytest test/ 32 | ``` 33 | 34 | ### Build & Publish 35 | ```shell 36 | python -m build 37 | twine upload dist/* 38 | ``` 39 | 40 | ### Generate Documentation with Sphinx 41 | - Install Sphinx and theme: 42 | ```shell 43 | pip install sphinx sphinx_rtd_theme 44 | ``` 45 | - Initialize Docs 46 | ```shell 47 | mkdir docs && cd docs 48 | sphinx-quickstart --sep -p PureMVC -a "Saad Shams" -v "2.0" -r "2.0.0" -l "en" 49 | ``` 50 | - Generate API docs and build HTML: 51 | ```shell 52 | cd ../ && sphinx-apidoc -o docs/source src/puremvc && cd docs && make html && cd .. && open docs/build/html/index.html 53 | ``` 54 | 55 | - To update docs after code changes: 56 | ```shell 57 | sphinx-apidoc -o docs/source src/puremvc --force && cd docs && make html && cd .. && open docs/build/html/index.html 58 | ``` 59 | - Snippet: conf.py 60 | ```python 61 | import os 62 | import sys 63 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'src'))) 64 | extensions = ['sphinx.ext.autodoc'] 65 | html_theme = 'sphinx_rtd_theme' 66 | ``` 67 | - Snippet: index.rst 68 | ``` 69 | 13: modules 70 | ``` 71 | --- 72 | 73 | ## Status 74 | Production - [Version 2.0.2](https://github.com/PureMVC/puremvc-python-multicore-framework/blob/master/VERSION) 75 | 76 | ## Platforms / Technologies 77 | * [Python](http://en.wikipedia.org/wiki/Python_(programming_language)) 78 | * [NumPy](https://numpy.org) 79 | * [Pandas](https://pandas.pydata.org) 80 | * [TensorFlow](https://www.tensorflow.org) 81 | * [PyTorch](https://pytorch.org) 82 | 83 | ## Reference 84 | 85 | * [PythonWheels](https://pythonwheels.com) 86 | * [Classifiers](https://pypi.org/classifiers/) 87 | * [Sphinx Documentation](https://www.sphinx-doc.org/en/master/index.html) 88 | * [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html) 89 | 90 | ## License 91 | * PureMVC MultiCore Framework for Python - Copyright © 2025 [Saad Shams](https://www.linkedin.com/in/muizz/) 92 | * PureMVC - Copyright © 2025 [Futurescale, Inc.](http://futurescale.com/) 93 | * All rights reserved. 94 | 95 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 96 | 97 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 98 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 99 | * Neither the name of Futurescale, Inc., PureMVC.org, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 100 | 101 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 102 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | PureMVC MultiCore Framework for Swift 2 | -------------------------------------------------------------------------- 3 | Release Date: 05/15/25 4 | Platform: Python 3 5 | Version: 2 6 | Revision: 0 7 | Minor: 1 8 | Author: Saad Shams 9 | -------------------------------------------------------------------------- 10 | 2.0.2 - Minor fixes 11 | 2.0.1 - Fix badge for README 12 | 2.0.0 - Brand new implementation of ported code, equivalent to AS3 MultiCore Version 1.0.5. 13 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 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) 21 | -------------------------------------------------------------------------------- /docs/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/modules.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/modules.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.core.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.core.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.interfaces.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.interfaces.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.patterns.command.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.patterns.command.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.patterns.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.patterns.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.patterns.facade.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.patterns.facade.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.patterns.mediator.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.patterns.mediator.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.patterns.observer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.patterns.observer.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/puremvc.patterns.proxy.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/doctrees/puremvc.patterns.proxy.doctree -------------------------------------------------------------------------------- /docs/build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 21e4320efea14d9e8c4803c57c253039 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. PureMVC documentation master file, created by 2 | sphinx-quickstart on Tue Jan 23 22:16:51 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PureMVC's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | modules 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/build/html/_sources/modules.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | puremvc 8 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.core.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.core package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.core.Controller module 8 | ------------------------------ 9 | 10 | .. automodule:: puremvc.core.Controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.core.Model module 16 | ------------------------- 17 | 18 | .. automodule:: puremvc.core.Model 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | puremvc.core.View module 24 | ------------------------ 25 | 26 | .. automodule:: puremvc.core.View 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: puremvc.core 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.interfaces.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.interfaces package 2 | ========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.interfaces.ICommand module 8 | ---------------------------------- 9 | 10 | .. automodule:: puremvc.interfaces.ICommand 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.interfaces.IController module 16 | ------------------------------------- 17 | 18 | .. automodule:: puremvc.interfaces.IController 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | puremvc.interfaces.IFacade module 24 | --------------------------------- 25 | 26 | .. automodule:: puremvc.interfaces.IFacade 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | puremvc.interfaces.IMediator module 32 | ----------------------------------- 33 | 34 | .. automodule:: puremvc.interfaces.IMediator 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | puremvc.interfaces.IModel module 40 | -------------------------------- 41 | 42 | .. automodule:: puremvc.interfaces.IModel 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | puremvc.interfaces.INotification module 48 | --------------------------------------- 49 | 50 | .. automodule:: puremvc.interfaces.INotification 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | puremvc.interfaces.INotifier module 56 | ----------------------------------- 57 | 58 | .. automodule:: puremvc.interfaces.INotifier 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | puremvc.interfaces.IObserver module 64 | ----------------------------------- 65 | 66 | .. automodule:: puremvc.interfaces.IObserver 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | puremvc.interfaces.IProxy module 72 | -------------------------------- 73 | 74 | .. automodule:: puremvc.interfaces.IProxy 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | puremvc.interfaces.IView module 80 | ------------------------------- 81 | 82 | .. automodule:: puremvc.interfaces.IView 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | Module contents 88 | --------------- 89 | 90 | .. automodule:: puremvc.interfaces 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.patterns.command.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.patterns.command package 2 | ================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.command.MacroCommand module 8 | -------------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.command.MacroCommand 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.patterns.command.SimpleCommand module 16 | --------------------------------------------- 17 | 18 | .. automodule:: puremvc.patterns.command.SimpleCommand 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: puremvc.patterns.command 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.patterns.facade.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.patterns.facade package 2 | =============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.facade.Facade module 8 | ------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.facade.Facade 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.patterns.facade.Notifier module 16 | --------------------------------------- 17 | 18 | .. automodule:: puremvc.patterns.facade.Notifier 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: puremvc.patterns.facade 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.patterns.mediator.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.patterns.mediator package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.mediator.Mediator module 8 | ----------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.mediator.Mediator 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: puremvc.patterns.mediator 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.patterns.observer.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.patterns.observer package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.observer.Notification module 8 | --------------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.observer.Notification 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.patterns.observer.Observer module 16 | ----------------------------------------- 17 | 18 | .. automodule:: puremvc.patterns.observer.Observer 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: puremvc.patterns.observer 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.patterns.proxy.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.patterns.proxy package 2 | ============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.proxy.Proxy module 8 | ----------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.proxy.Proxy 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: puremvc.patterns.proxy 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.patterns.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc.patterns package 2 | ======================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | puremvc.patterns.command 11 | puremvc.patterns.facade 12 | puremvc.patterns.mediator 13 | puremvc.patterns.observer 14 | puremvc.patterns.proxy 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: puremvc.patterns 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/build/html/_sources/puremvc.rst.txt: -------------------------------------------------------------------------------- 1 | puremvc package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | puremvc.core 11 | puremvc.interfaces 12 | puremvc.patterns 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: puremvc 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/build/html/_static/_sphinx_javascript_frameworks_compat.js: -------------------------------------------------------------------------------- 1 | /* Compatability shim for jQuery and underscores.js. 2 | * 3 | * Copyright Sphinx contributors 4 | * Released under the two clause BSD licence 5 | */ 6 | 7 | /** 8 | * small helper function to urldecode strings 9 | * 10 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL 11 | */ 12 | jQuery.urldecode = function(x) { 13 | if (!x) { 14 | return x 15 | } 16 | return decodeURIComponent(x.replace(/\+/g, ' ')); 17 | }; 18 | 19 | /** 20 | * small helper function to urlencode strings 21 | */ 22 | jQuery.urlencode = encodeURIComponent; 23 | 24 | /** 25 | * This function returns the parsed url parameters of the 26 | * current request. Multiple values per key are supported, 27 | * it will always return arrays of strings for the value parts. 28 | */ 29 | jQuery.getQueryParameters = function(s) { 30 | if (typeof s === 'undefined') 31 | s = document.location.search; 32 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 33 | var result = {}; 34 | for (var i = 0; i < parts.length; i++) { 35 | var tmp = parts[i].split('=', 2); 36 | var key = jQuery.urldecode(tmp[0]); 37 | var value = jQuery.urldecode(tmp[1]); 38 | if (key in result) 39 | result[key].push(value); 40 | else 41 | result[key] = [value]; 42 | } 43 | return result; 44 | }; 45 | 46 | /** 47 | * highlight a given string on a jquery object by wrapping it in 48 | * span elements with the given class name. 49 | */ 50 | jQuery.fn.highlightText = function(text, className) { 51 | function highlight(node, addItems) { 52 | if (node.nodeType === 3) { 53 | var val = node.nodeValue; 54 | var pos = val.toLowerCase().indexOf(text); 55 | if (pos >= 0 && 56 | !jQuery(node.parentNode).hasClass(className) && 57 | !jQuery(node.parentNode).hasClass("nohighlight")) { 58 | var span; 59 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); 60 | if (isInSVG) { 61 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 62 | } else { 63 | span = document.createElement("span"); 64 | span.className = className; 65 | } 66 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 67 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 68 | document.createTextNode(val.substr(pos + text.length)), 69 | node.nextSibling)); 70 | node.nodeValue = val.substr(0, pos); 71 | if (isInSVG) { 72 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); 73 | var bbox = node.parentElement.getBBox(); 74 | rect.x.baseVal.value = bbox.x; 75 | rect.y.baseVal.value = bbox.y; 76 | rect.width.baseVal.value = bbox.width; 77 | rect.height.baseVal.value = bbox.height; 78 | rect.setAttribute('class', className); 79 | addItems.push({ 80 | "parent": node.parentNode, 81 | "target": rect}); 82 | } 83 | } 84 | } 85 | else if (!jQuery(node).is("button, select, textarea")) { 86 | jQuery.each(node.childNodes, function() { 87 | highlight(this, addItems); 88 | }); 89 | } 90 | } 91 | var addItems = []; 92 | var result = this.each(function() { 93 | highlight(this, addItems); 94 | }); 95 | for (var i = 0; i < addItems.length; ++i) { 96 | jQuery(addItems[i].parent).before(addItems[i].target); 97 | } 98 | return result; 99 | }; 100 | 101 | /* 102 | * backward compatibility for jQuery.browser 103 | * This will be supported until firefox bug is fixed. 104 | */ 105 | if (!jQuery.browser) { 106 | jQuery.uaMatch = function(ua) { 107 | ua = ua.toLowerCase(); 108 | 109 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 110 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 111 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 112 | /(msie) ([\w.]+)/.exec(ua) || 113 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 114 | []; 115 | 116 | return { 117 | browser: match[ 1 ] || "", 118 | version: match[ 2 ] || "0" 119 | }; 120 | }; 121 | jQuery.browser = {}; 122 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 123 | } 124 | -------------------------------------------------------------------------------- /docs/build/html/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions .rst-other-versions .rtd-current-item{font-weight:700}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}#flyout-search-form{padding:6px} -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-bold-italic.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-bold-italic.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-bold.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-bold.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-normal-italic.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-normal-italic.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-normal.woff -------------------------------------------------------------------------------- /docs/build/html/_static/css/fonts/lato-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/css/fonts/lato-normal.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Base JavaScript utilities for all Sphinx HTML documentation. 6 | * 7 | * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | "use strict"; 12 | 13 | const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ 14 | "TEXTAREA", 15 | "INPUT", 16 | "SELECT", 17 | "BUTTON", 18 | ]); 19 | 20 | const _ready = (callback) => { 21 | if (document.readyState !== "loading") { 22 | callback(); 23 | } else { 24 | document.addEventListener("DOMContentLoaded", callback); 25 | } 26 | }; 27 | 28 | /** 29 | * Small JavaScript module for the documentation. 30 | */ 31 | const Documentation = { 32 | init: () => { 33 | Documentation.initDomainIndexTable(); 34 | Documentation.initOnKeyListeners(); 35 | }, 36 | 37 | /** 38 | * i18n support 39 | */ 40 | TRANSLATIONS: {}, 41 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 42 | LOCALE: "unknown", 43 | 44 | // gettext and ngettext don't access this so that the functions 45 | // can safely bound to a different name (_ = Documentation.gettext) 46 | gettext: (string) => { 47 | const translated = Documentation.TRANSLATIONS[string]; 48 | switch (typeof translated) { 49 | case "undefined": 50 | return string; // no translation 51 | case "string": 52 | return translated; // translation exists 53 | default: 54 | return translated[0]; // (singular, plural) translation tuple exists 55 | } 56 | }, 57 | 58 | ngettext: (singular, plural, n) => { 59 | const translated = Documentation.TRANSLATIONS[singular]; 60 | if (typeof translated !== "undefined") 61 | return translated[Documentation.PLURAL_EXPR(n)]; 62 | return n === 1 ? singular : plural; 63 | }, 64 | 65 | addTranslations: (catalog) => { 66 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 67 | Documentation.PLURAL_EXPR = new Function( 68 | "n", 69 | `return (${catalog.plural_expr})` 70 | ); 71 | Documentation.LOCALE = catalog.locale; 72 | }, 73 | 74 | /** 75 | * helper function to focus on search bar 76 | */ 77 | focusSearchBar: () => { 78 | document.querySelectorAll("input[name=q]")[0]?.focus(); 79 | }, 80 | 81 | /** 82 | * Initialise the domain index toggle buttons 83 | */ 84 | initDomainIndexTable: () => { 85 | const toggler = (el) => { 86 | const idNumber = el.id.substr(7); 87 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 88 | if (el.src.substr(-9) === "minus.png") { 89 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 90 | toggledRows.forEach((el) => (el.style.display = "none")); 91 | } else { 92 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 93 | toggledRows.forEach((el) => (el.style.display = "")); 94 | } 95 | }; 96 | 97 | const togglerElements = document.querySelectorAll("img.toggler"); 98 | togglerElements.forEach((el) => 99 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 100 | ); 101 | togglerElements.forEach((el) => (el.style.display = "")); 102 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 103 | }, 104 | 105 | initOnKeyListeners: () => { 106 | // only install a listener if it is really needed 107 | if ( 108 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 109 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 110 | ) 111 | return; 112 | 113 | document.addEventListener("keydown", (event) => { 114 | // bail for input elements 115 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 116 | // bail with special keys 117 | if (event.altKey || event.ctrlKey || event.metaKey) return; 118 | 119 | if (!event.shiftKey) { 120 | switch (event.key) { 121 | case "ArrowLeft": 122 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 123 | 124 | const prevLink = document.querySelector('link[rel="prev"]'); 125 | if (prevLink && prevLink.href) { 126 | window.location.href = prevLink.href; 127 | event.preventDefault(); 128 | } 129 | break; 130 | case "ArrowRight": 131 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 132 | 133 | const nextLink = document.querySelector('link[rel="next"]'); 134 | if (nextLink && nextLink.href) { 135 | window.location.href = nextLink.href; 136 | event.preventDefault(); 137 | } 138 | break; 139 | } 140 | } 141 | 142 | // some keyboard layouts may need Shift to get / 143 | switch (event.key) { 144 | case "/": 145 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 146 | Documentation.focusSearchBar(); 147 | event.preventDefault(); 148 | } 149 | }); 150 | }, 151 | }; 152 | 153 | // quick alias for translations 154 | const _ = Documentation.gettext; 155 | 156 | _ready(Documentation.init); 157 | -------------------------------------------------------------------------------- /docs/build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | const DOCUMENTATION_OPTIONS = { 2 | VERSION: '2.0.2', 3 | LANGUAGE: 'en', 4 | COLLAPSE_INDEX: false, 5 | BUILDER: 'html', 6 | FILE_SUFFIX: '.html', 7 | LINK_SUFFIX: '.html', 8 | HAS_SOURCE: true, 9 | SOURCELINK_SUFFIX: '.txt', 10 | NAVIGATION_WITH_KEYS: false, 11 | SHOW_SEARCH_SUMMARY: true, 12 | ENABLE_SEARCH_SHORTCUTS: true, 13 | }; -------------------------------------------------------------------------------- /docs/build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/file.png -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bold.eot -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bold.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bold.woff -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bold.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bolditalic.eot -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bolditalic.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bolditalic.woff -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-bolditalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-bolditalic.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-italic.eot -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-italic.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-italic.woff -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-italic.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-regular.eot -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-regular.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-regular.woff -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/Lato/lato-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/Lato/lato-regular.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff -------------------------------------------------------------------------------- /docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 -------------------------------------------------------------------------------- /docs/build/html/_static/js/badge_only.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); -------------------------------------------------------------------------------- /docs/build/html/_static/js/html5shiv-printshiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /docs/build/html/_static/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /docs/build/html/_static/js/theme.js: -------------------------------------------------------------------------------- 1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t a.language.name.localeCompare(b.language.name)); 14 | 15 | const languagesHTML = ` 16 |
17 |
Languages
18 | ${languages 19 | .map( 20 | (translation) => ` 21 |
22 | ${translation.language.code} 23 |
24 | `, 25 | ) 26 | .join("\n")} 27 |
28 | `; 29 | return languagesHTML; 30 | } 31 | 32 | function renderVersions(config) { 33 | if (!config.versions.active.length) { 34 | return ""; 35 | } 36 | const versionsHTML = ` 37 |
38 |
Versions
39 | ${config.versions.active 40 | .map( 41 | (version) => ` 42 |
43 | ${version.slug} 44 |
45 | `, 46 | ) 47 | .join("\n")} 48 |
49 | `; 50 | return versionsHTML; 51 | } 52 | 53 | function renderDownloads(config) { 54 | if (!Object.keys(config.versions.current.downloads).length) { 55 | return ""; 56 | } 57 | const downloadsNameDisplay = { 58 | pdf: "PDF", 59 | epub: "Epub", 60 | htmlzip: "HTML", 61 | }; 62 | 63 | const downloadsHTML = ` 64 |
65 |
Downloads
66 | ${Object.entries(config.versions.current.downloads) 67 | .map( 68 | ([name, url]) => ` 69 |
70 | ${downloadsNameDisplay[name]} 71 |
72 | `, 73 | ) 74 | .join("\n")} 75 |
76 | `; 77 | return downloadsHTML; 78 | } 79 | 80 | document.addEventListener("readthedocs-addons-data-ready", function (event) { 81 | const config = event.detail.data(); 82 | 83 | const flyout = ` 84 |
85 | 86 | Read the Docs 87 | v: ${config.versions.current.slug} 88 | 89 | 90 |
91 |
92 | ${renderLanguages(config)} 93 | ${renderVersions(config)} 94 | ${renderDownloads(config)} 95 |
96 |
On Read the Docs
97 |
98 | Project Home 99 |
100 |
101 | Builds 102 |
103 |
104 | Downloads 105 |
106 |
107 |
108 |
Search
109 |
110 |
111 | 118 |
119 |
120 |
121 |
122 | 123 | Hosted by Read the Docs 124 | 125 |
126 |
127 | `; 128 | 129 | // Inject the generated flyout into the body HTML element. 130 | document.body.insertAdjacentHTML("beforeend", flyout); 131 | 132 | // Trigger the Read the Docs Addons Search modal when clicking on the "Search docs" input from inside the flyout. 133 | document 134 | .querySelector("#flyout-search-form") 135 | .addEventListener("focusin", () => { 136 | const event = new CustomEvent("readthedocs-search-show"); 137 | document.dispatchEvent(event); 138 | }); 139 | }) 140 | } 141 | 142 | if (themeLanguageSelector || themeVersionSelector) { 143 | function onSelectorSwitch(event) { 144 | const option = event.target.selectedIndex; 145 | const item = event.target.options[option]; 146 | window.location.href = item.dataset.url; 147 | } 148 | 149 | document.addEventListener("readthedocs-addons-data-ready", function (event) { 150 | const config = event.detail.data(); 151 | 152 | const versionSwitch = document.querySelector( 153 | "div.switch-menus > div.version-switch", 154 | ); 155 | if (themeVersionSelector) { 156 | let versions = config.versions.active; 157 | if (config.versions.current.hidden || config.versions.current.type === "external") { 158 | versions.unshift(config.versions.current); 159 | } 160 | const versionSelect = ` 161 | 174 | `; 175 | 176 | versionSwitch.innerHTML = versionSelect; 177 | versionSwitch.firstElementChild.addEventListener("change", onSelectorSwitch); 178 | } 179 | 180 | const languageSwitch = document.querySelector( 181 | "div.switch-menus > div.language-switch", 182 | ); 183 | 184 | if (themeLanguageSelector) { 185 | if (config.projects.translations.length) { 186 | // Add the current language to the options on the selector 187 | let languages = config.projects.translations.concat( 188 | config.projects.current, 189 | ); 190 | languages = languages.sort((a, b) => 191 | a.language.name.localeCompare(b.language.name), 192 | ); 193 | 194 | const languageSelect = ` 195 | 208 | `; 209 | 210 | languageSwitch.innerHTML = languageSelect; 211 | languageSwitch.firstElementChild.addEventListener("change", onSelectorSwitch); 212 | } 213 | else { 214 | languageSwitch.remove(); 215 | } 216 | } 217 | }); 218 | } 219 | 220 | document.addEventListener("readthedocs-addons-data-ready", function (event) { 221 | // Trigger the Read the Docs Addons Search modal when clicking on "Search docs" input from the topnav. 222 | document 223 | .querySelector("[role='search'] input") 224 | .addEventListener("focusin", () => { 225 | const event = new CustomEvent("readthedocs-search-show"); 226 | document.dispatchEvent(event); 227 | }); 228 | }); -------------------------------------------------------------------------------- /docs/build/html/_static/language_data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * language_data.js 3 | * ~~~~~~~~~~~~~~~~ 4 | * 5 | * This script contains the language-specific data used by searchtools.js, 6 | * namely the list of stopwords, stemmer, scorer and splitter. 7 | * 8 | * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. 9 | * :license: BSD, see LICENSE for details. 10 | * 11 | */ 12 | 13 | var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; 14 | 15 | 16 | /* Non-minified version is copied as a separate JS file, if available */ 17 | 18 | /** 19 | * Porter Stemmer 20 | */ 21 | var Stemmer = function() { 22 | 23 | var step2list = { 24 | ational: 'ate', 25 | tional: 'tion', 26 | enci: 'ence', 27 | anci: 'ance', 28 | izer: 'ize', 29 | bli: 'ble', 30 | alli: 'al', 31 | entli: 'ent', 32 | eli: 'e', 33 | ousli: 'ous', 34 | ization: 'ize', 35 | ation: 'ate', 36 | ator: 'ate', 37 | alism: 'al', 38 | iveness: 'ive', 39 | fulness: 'ful', 40 | ousness: 'ous', 41 | aliti: 'al', 42 | iviti: 'ive', 43 | biliti: 'ble', 44 | logi: 'log' 45 | }; 46 | 47 | var step3list = { 48 | icate: 'ic', 49 | ative: '', 50 | alize: 'al', 51 | iciti: 'ic', 52 | ical: 'ic', 53 | ful: '', 54 | ness: '' 55 | }; 56 | 57 | var c = "[^aeiou]"; // consonant 58 | var v = "[aeiouy]"; // vowel 59 | var C = c + "[^aeiouy]*"; // consonant sequence 60 | var V = v + "[aeiou]*"; // vowel sequence 61 | 62 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 63 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 64 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 65 | var s_v = "^(" + C + ")?" + v; // vowel in stem 66 | 67 | this.stemWord = function (w) { 68 | var stem; 69 | var suffix; 70 | var firstch; 71 | var origword = w; 72 | 73 | if (w.length < 3) 74 | return w; 75 | 76 | var re; 77 | var re2; 78 | var re3; 79 | var re4; 80 | 81 | firstch = w.substr(0,1); 82 | if (firstch == "y") 83 | w = firstch.toUpperCase() + w.substr(1); 84 | 85 | // Step 1a 86 | re = /^(.+?)(ss|i)es$/; 87 | re2 = /^(.+?)([^s])s$/; 88 | 89 | if (re.test(w)) 90 | w = w.replace(re,"$1$2"); 91 | else if (re2.test(w)) 92 | w = w.replace(re2,"$1$2"); 93 | 94 | // Step 1b 95 | re = /^(.+?)eed$/; 96 | re2 = /^(.+?)(ed|ing)$/; 97 | if (re.test(w)) { 98 | var fp = re.exec(w); 99 | re = new RegExp(mgr0); 100 | if (re.test(fp[1])) { 101 | re = /.$/; 102 | w = w.replace(re,""); 103 | } 104 | } 105 | else if (re2.test(w)) { 106 | var fp = re2.exec(w); 107 | stem = fp[1]; 108 | re2 = new RegExp(s_v); 109 | if (re2.test(stem)) { 110 | w = stem; 111 | re2 = /(at|bl|iz)$/; 112 | re3 = new RegExp("([^aeiouylsz])\\1$"); 113 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 114 | if (re2.test(w)) 115 | w = w + "e"; 116 | else if (re3.test(w)) { 117 | re = /.$/; 118 | w = w.replace(re,""); 119 | } 120 | else if (re4.test(w)) 121 | w = w + "e"; 122 | } 123 | } 124 | 125 | // Step 1c 126 | re = /^(.+?)y$/; 127 | if (re.test(w)) { 128 | var fp = re.exec(w); 129 | stem = fp[1]; 130 | re = new RegExp(s_v); 131 | if (re.test(stem)) 132 | w = stem + "i"; 133 | } 134 | 135 | // Step 2 136 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 137 | if (re.test(w)) { 138 | var fp = re.exec(w); 139 | stem = fp[1]; 140 | suffix = fp[2]; 141 | re = new RegExp(mgr0); 142 | if (re.test(stem)) 143 | w = stem + step2list[suffix]; 144 | } 145 | 146 | // Step 3 147 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 148 | if (re.test(w)) { 149 | var fp = re.exec(w); 150 | stem = fp[1]; 151 | suffix = fp[2]; 152 | re = new RegExp(mgr0); 153 | if (re.test(stem)) 154 | w = stem + step3list[suffix]; 155 | } 156 | 157 | // Step 4 158 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 159 | re2 = /^(.+?)(s|t)(ion)$/; 160 | if (re.test(w)) { 161 | var fp = re.exec(w); 162 | stem = fp[1]; 163 | re = new RegExp(mgr1); 164 | if (re.test(stem)) 165 | w = stem; 166 | } 167 | else if (re2.test(w)) { 168 | var fp = re2.exec(w); 169 | stem = fp[1] + fp[2]; 170 | re2 = new RegExp(mgr1); 171 | if (re2.test(stem)) 172 | w = stem; 173 | } 174 | 175 | // Step 5 176 | re = /^(.+?)e$/; 177 | if (re.test(w)) { 178 | var fp = re.exec(w); 179 | stem = fp[1]; 180 | re = new RegExp(mgr1); 181 | re2 = new RegExp(meq1); 182 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 183 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 184 | w = stem; 185 | } 186 | re = /ll$/; 187 | re2 = new RegExp(mgr1); 188 | if (re.test(w) && re2.test(w)) { 189 | re = /.$/; 190 | w = w.replace(re,""); 191 | } 192 | 193 | // and turn initial Y back to y 194 | if (firstch == "y") 195 | w = firstch.toLowerCase() + w.substr(1); 196 | return w; 197 | } 198 | } 199 | 200 | -------------------------------------------------------------------------------- /docs/build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | pre { line-height: 125%; } 2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 6 | .highlight .hll { background-color: #ffffcc } 7 | .highlight { background: #f8f8f8; } 8 | .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ 9 | .highlight .err { border: 1px solid #F00 } /* Error */ 10 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */ 11 | .highlight .o { color: #666 } /* Operator */ 12 | .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ 13 | .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ 14 | .highlight .cp { color: #9C6500 } /* Comment.Preproc */ 15 | .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ 16 | .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ 17 | .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ 18 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 19 | .highlight .ge { font-style: italic } /* Generic.Emph */ 20 | .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ 21 | .highlight .gr { color: #E40000 } /* Generic.Error */ 22 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 23 | .highlight .gi { color: #008400 } /* Generic.Inserted */ 24 | .highlight .go { color: #717171 } /* Generic.Output */ 25 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 26 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 27 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 28 | .highlight .gt { color: #04D } /* Generic.Traceback */ 29 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 30 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 31 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 32 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */ 33 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 34 | .highlight .kt { color: #B00040 } /* Keyword.Type */ 35 | .highlight .m { color: #666 } /* Literal.Number */ 36 | .highlight .s { color: #BA2121 } /* Literal.String */ 37 | .highlight .na { color: #687822 } /* Name.Attribute */ 38 | .highlight .nb { color: #008000 } /* Name.Builtin */ 39 | .highlight .nc { color: #00F; font-weight: bold } /* Name.Class */ 40 | .highlight .no { color: #800 } /* Name.Constant */ 41 | .highlight .nd { color: #A2F } /* Name.Decorator */ 42 | .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ 43 | .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ 44 | .highlight .nf { color: #00F } /* Name.Function */ 45 | .highlight .nl { color: #767600 } /* Name.Label */ 46 | .highlight .nn { color: #00F; font-weight: bold } /* Name.Namespace */ 47 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ 48 | .highlight .nv { color: #19177C } /* Name.Variable */ 49 | .highlight .ow { color: #A2F; font-weight: bold } /* Operator.Word */ 50 | .highlight .w { color: #BBB } /* Text.Whitespace */ 51 | .highlight .mb { color: #666 } /* Literal.Number.Bin */ 52 | .highlight .mf { color: #666 } /* Literal.Number.Float */ 53 | .highlight .mh { color: #666 } /* Literal.Number.Hex */ 54 | .highlight .mi { color: #666 } /* Literal.Number.Integer */ 55 | .highlight .mo { color: #666 } /* Literal.Number.Oct */ 56 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */ 57 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ 58 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */ 59 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ 60 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 61 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ 62 | .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ 63 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ 64 | .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ 65 | .highlight .sx { color: #008000 } /* Literal.String.Other */ 66 | .highlight .sr { color: #A45A77 } /* Literal.String.Regex */ 67 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ 68 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */ 69 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ 70 | .highlight .fm { color: #00F } /* Name.Function.Magic */ 71 | .highlight .vc { color: #19177C } /* Name.Variable.Class */ 72 | .highlight .vg { color: #19177C } /* Name.Variable.Global */ 73 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */ 74 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */ 75 | .highlight .il { color: #666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/build/html/_static/sphinx_highlight.js: -------------------------------------------------------------------------------- 1 | /* Highlighting utilities for Sphinx HTML documentation. */ 2 | "use strict"; 3 | 4 | const SPHINX_HIGHLIGHT_ENABLED = true 5 | 6 | /** 7 | * highlight a given string on a node by wrapping it in 8 | * span elements with the given class name. 9 | */ 10 | const _highlight = (node, addItems, text, className) => { 11 | if (node.nodeType === Node.TEXT_NODE) { 12 | const val = node.nodeValue; 13 | const parent = node.parentNode; 14 | const pos = val.toLowerCase().indexOf(text); 15 | if ( 16 | pos >= 0 && 17 | !parent.classList.contains(className) && 18 | !parent.classList.contains("nohighlight") 19 | ) { 20 | let span; 21 | 22 | const closestNode = parent.closest("body, svg, foreignObject"); 23 | const isInSVG = closestNode && closestNode.matches("svg"); 24 | if (isInSVG) { 25 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 26 | } else { 27 | span = document.createElement("span"); 28 | span.classList.add(className); 29 | } 30 | 31 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 32 | const rest = document.createTextNode(val.substr(pos + text.length)); 33 | parent.insertBefore( 34 | span, 35 | parent.insertBefore( 36 | rest, 37 | node.nextSibling 38 | ) 39 | ); 40 | node.nodeValue = val.substr(0, pos); 41 | /* There may be more occurrences of search term in this node. So call this 42 | * function recursively on the remaining fragment. 43 | */ 44 | _highlight(rest, addItems, text, className); 45 | 46 | if (isInSVG) { 47 | const rect = document.createElementNS( 48 | "http://www.w3.org/2000/svg", 49 | "rect" 50 | ); 51 | const bbox = parent.getBBox(); 52 | rect.x.baseVal.value = bbox.x; 53 | rect.y.baseVal.value = bbox.y; 54 | rect.width.baseVal.value = bbox.width; 55 | rect.height.baseVal.value = bbox.height; 56 | rect.setAttribute("class", className); 57 | addItems.push({ parent: parent, target: rect }); 58 | } 59 | } 60 | } else if (node.matches && !node.matches("button, select, textarea")) { 61 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); 62 | } 63 | }; 64 | const _highlightText = (thisNode, text, className) => { 65 | let addItems = []; 66 | _highlight(thisNode, addItems, text, className); 67 | addItems.forEach((obj) => 68 | obj.parent.insertAdjacentElement("beforebegin", obj.target) 69 | ); 70 | }; 71 | 72 | /** 73 | * Small JavaScript module for the documentation. 74 | */ 75 | const SphinxHighlight = { 76 | 77 | /** 78 | * highlight the search words provided in localstorage in the text 79 | */ 80 | highlightSearchWords: () => { 81 | if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight 82 | 83 | // get and clear terms from localstorage 84 | const url = new URL(window.location); 85 | const highlight = 86 | localStorage.getItem("sphinx_highlight_terms") 87 | || url.searchParams.get("highlight") 88 | || ""; 89 | localStorage.removeItem("sphinx_highlight_terms") 90 | url.searchParams.delete("highlight"); 91 | window.history.replaceState({}, "", url); 92 | 93 | // get individual terms from highlight string 94 | const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); 95 | if (terms.length === 0) return; // nothing to do 96 | 97 | // There should never be more than one element matching "div.body" 98 | const divBody = document.querySelectorAll("div.body"); 99 | const body = divBody.length ? divBody[0] : document.querySelector("body"); 100 | window.setTimeout(() => { 101 | terms.forEach((term) => _highlightText(body, term, "highlighted")); 102 | }, 10); 103 | 104 | const searchBox = document.getElementById("searchbox"); 105 | if (searchBox === null) return; 106 | searchBox.appendChild( 107 | document 108 | .createRange() 109 | .createContextualFragment( 110 | '" 114 | ) 115 | ); 116 | }, 117 | 118 | /** 119 | * helper function to hide the search marks again 120 | */ 121 | hideSearchWords: () => { 122 | document 123 | .querySelectorAll("#searchbox .highlight-link") 124 | .forEach((el) => el.remove()); 125 | document 126 | .querySelectorAll("span.highlighted") 127 | .forEach((el) => el.classList.remove("highlighted")); 128 | localStorage.removeItem("sphinx_highlight_terms") 129 | }, 130 | 131 | initEscapeListener: () => { 132 | // only install a listener if it is really needed 133 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; 134 | 135 | document.addEventListener("keydown", (event) => { 136 | // bail for input elements 137 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 138 | // bail with special keys 139 | if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; 140 | if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { 141 | SphinxHighlight.hideSearchWords(); 142 | event.preventDefault(); 143 | } 144 | }); 145 | }, 146 | }; 147 | 148 | _ready(() => { 149 | /* Do not call highlightSearchWords() when we are on the search page. 150 | * It will highlight words from the *previous* search query. 151 | */ 152 | if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); 153 | SphinxHighlight.initEscapeListener(); 154 | }); 155 | -------------------------------------------------------------------------------- /docs/build/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to PureMVC’s documentation! — PureMVC 2.0.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 52 | 53 |
57 | 58 |
59 |
60 |
61 |
    62 |
  • 63 | 64 |
  • 65 | View page source 66 |
  • 67 |
68 |
69 |
70 |
71 |
72 | 73 |
74 |

Welcome to PureMVC’s documentation!

75 |
76 |

Contents:

77 | 83 |
84 |
85 |
86 |

Indices and tables

87 | 92 |
93 | 94 | 95 |
96 |
97 |
100 | 101 |
102 | 103 |
104 |

© Copyright 2025, Saad Shams.

105 |
106 | 107 | Built with Sphinx using a 108 | theme 109 | provided by Read the Docs. 110 | 111 | 112 |
113 |
114 |
115 |
116 |
117 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /docs/build/html/modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | puremvc — PureMVC 2.0.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 56 | 57 |
61 | 62 |
63 |
64 |
65 | 72 |
73 |
74 | 123 |
127 | 128 |
129 | 130 |
131 |

© Copyright 2025, Saad Shams.

132 |
133 | 134 | Built with Sphinx using a 135 | theme 136 | provided by Read the Docs. 137 | 138 | 139 |
140 |
141 |
142 |
143 |
144 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/docs/build/html/objects.inv -------------------------------------------------------------------------------- /docs/build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Search — PureMVC 2.0.2 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 53 | 54 |
58 | 59 |
60 |
61 |
62 |
    63 |
  • 64 | 65 |
  • 66 |
  • 67 |
68 |
69 |
70 |
71 |
72 | 73 | 80 | 81 | 82 |
83 | 84 |
85 | 86 |
87 |
88 |
89 | 90 |
91 | 92 |
93 |

© Copyright 2025, Saad Shams.

94 |
95 | 96 | Built with Sphinx using a 97 | theme 98 | provided by Read the Docs. 99 | 100 | 101 |
102 |
103 |
104 |
105 |
106 | 111 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /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=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | import os 7 | import sys 8 | 9 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'src'))) 10 | 11 | # -- Project information ----------------------------------------------------- 12 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 13 | 14 | project = 'PureMVC' 15 | copyright = '2025, Saad Shams' 16 | author = 'Saad Shams' 17 | 18 | version = '2.0' 19 | release = '2.0.2' 20 | 21 | # -- General configuration --------------------------------------------------- 22 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 23 | 24 | extensions = ['sphinx.ext.autodoc'] 25 | 26 | templates_path = ['_templates'] 27 | exclude_patterns = [] 28 | 29 | language = 'en' 30 | 31 | # -- Options for HTML output ------------------------------------------------- 32 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 33 | 34 | html_theme = 'sphinx_rtd_theme' 35 | html_static_path = ['_static'] 36 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. PureMVC documentation master file, created by 2 | sphinx-quickstart on Tue Jan 23 22:16:51 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PureMVC's documentation! 7 | =================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | modules 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | puremvc 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | puremvc 8 | -------------------------------------------------------------------------------- /docs/source/puremvc.core.rst: -------------------------------------------------------------------------------- 1 | puremvc.core package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.core.Controller module 8 | ------------------------------ 9 | 10 | .. automodule:: puremvc.core.Controller 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.core.Model module 16 | ------------------------- 17 | 18 | .. automodule:: puremvc.core.Model 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | puremvc.core.View module 24 | ------------------------ 25 | 26 | .. automodule:: puremvc.core.View 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: puremvc.core 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /docs/source/puremvc.interfaces.rst: -------------------------------------------------------------------------------- 1 | puremvc.interfaces package 2 | ========================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.interfaces.ICommand module 8 | ---------------------------------- 9 | 10 | .. automodule:: puremvc.interfaces.ICommand 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.interfaces.IController module 16 | ------------------------------------- 17 | 18 | .. automodule:: puremvc.interfaces.IController 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | puremvc.interfaces.IFacade module 24 | --------------------------------- 25 | 26 | .. automodule:: puremvc.interfaces.IFacade 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | puremvc.interfaces.IMediator module 32 | ----------------------------------- 33 | 34 | .. automodule:: puremvc.interfaces.IMediator 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | puremvc.interfaces.IModel module 40 | -------------------------------- 41 | 42 | .. automodule:: puremvc.interfaces.IModel 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | puremvc.interfaces.INotification module 48 | --------------------------------------- 49 | 50 | .. automodule:: puremvc.interfaces.INotification 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | puremvc.interfaces.INotifier module 56 | ----------------------------------- 57 | 58 | .. automodule:: puremvc.interfaces.INotifier 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | puremvc.interfaces.IObserver module 64 | ----------------------------------- 65 | 66 | .. automodule:: puremvc.interfaces.IObserver 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | puremvc.interfaces.IProxy module 72 | -------------------------------- 73 | 74 | .. automodule:: puremvc.interfaces.IProxy 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | puremvc.interfaces.IView module 80 | ------------------------------- 81 | 82 | .. automodule:: puremvc.interfaces.IView 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | Module contents 88 | --------------- 89 | 90 | .. automodule:: puremvc.interfaces 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | -------------------------------------------------------------------------------- /docs/source/puremvc.patterns.command.rst: -------------------------------------------------------------------------------- 1 | puremvc.patterns.command package 2 | ================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.command.MacroCommand module 8 | -------------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.command.MacroCommand 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.patterns.command.SimpleCommand module 16 | --------------------------------------------- 17 | 18 | .. automodule:: puremvc.patterns.command.SimpleCommand 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: puremvc.patterns.command 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/puremvc.patterns.facade.rst: -------------------------------------------------------------------------------- 1 | puremvc.patterns.facade package 2 | =============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.facade.Facade module 8 | ------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.facade.Facade 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.patterns.facade.Notifier module 16 | --------------------------------------- 17 | 18 | .. automodule:: puremvc.patterns.facade.Notifier 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: puremvc.patterns.facade 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/puremvc.patterns.mediator.rst: -------------------------------------------------------------------------------- 1 | puremvc.patterns.mediator package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.mediator.Mediator module 8 | ----------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.mediator.Mediator 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: puremvc.patterns.mediator 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/puremvc.patterns.observer.rst: -------------------------------------------------------------------------------- 1 | puremvc.patterns.observer package 2 | ================================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.observer.Notification module 8 | --------------------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.observer.Notification 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | puremvc.patterns.observer.Observer module 16 | ----------------------------------------- 17 | 18 | .. automodule:: puremvc.patterns.observer.Observer 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: puremvc.patterns.observer 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/puremvc.patterns.proxy.rst: -------------------------------------------------------------------------------- 1 | puremvc.patterns.proxy package 2 | ============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | puremvc.patterns.proxy.Proxy module 8 | ----------------------------------- 9 | 10 | .. automodule:: puremvc.patterns.proxy.Proxy 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: puremvc.patterns.proxy 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/puremvc.patterns.rst: -------------------------------------------------------------------------------- 1 | puremvc.patterns package 2 | ======================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | puremvc.patterns.command 11 | puremvc.patterns.facade 12 | puremvc.patterns.mediator 13 | puremvc.patterns.observer 14 | puremvc.patterns.proxy 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: puremvc.patterns 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/puremvc.rst: -------------------------------------------------------------------------------- 1 | puremvc package 2 | =============== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | puremvc.core 11 | puremvc.interfaces 12 | puremvc.patterns 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: puremvc 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "PureMVC" 7 | version = "2.0.1" 8 | requires-python = ">=3.8" 9 | authors = [{ name = "Saad Shams", email = "saad.shams@puremvc.org" }] 10 | description = "PureMVC Multicore Framework" 11 | readme = "README.md" 12 | license = "BSD-3-Clause" 13 | keywords = ["puremvc", "mvc", "model", "view", "controller", "patterns"] 14 | classifiers = [ 15 | "Development Status :: 5 - Production/Stable", 16 | "Intended Audience :: Developers", 17 | "Programming Language :: Python :: 3", 18 | "Topic :: Utilities" 19 | ] 20 | 21 | [project.urls] 22 | Homepage = "https://puremvc.org" 23 | Source = "https://github.com/PureMVC/puremvc-python-multicore-framework" 24 | Documentation = "https://puremvc.org/pages/docs/Python/multicore" 25 | 26 | [tool.mypy] 27 | python_version = "3.9" 28 | mypy_path = ["src"] 29 | explicit_package_bases = true 30 | namespace_packages = true 31 | ignore_missing_imports = false 32 | disallow_untyped_defs = true 33 | disallow_incomplete_defs = true 34 | check_untyped_defs = true 35 | warn_unused_ignores = true 36 | warn_return_any = true 37 | warn_unused_configs = true 38 | strict_equality = true 39 | show_error_codes = true 40 | pretty = true 41 | -------------------------------------------------------------------------------- /src/puremvc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/src/puremvc/__init__.py -------------------------------------------------------------------------------- /src/puremvc/core/Controller.py: -------------------------------------------------------------------------------- 1 | # Controller.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import threading 8 | from typing import Dict, Callable, Optional 9 | 10 | from puremvc.interfaces import IController, ICommand, IView, INotification 11 | from puremvc.patterns.observer import Observer 12 | from .View import View 13 | 14 | 15 | class Controller(IController): 16 | """ 17 | A Multiton `IController` implementation. 18 | 19 | In PureMVC, the `Controller` class follows the 20 | 'Command and Controller' strategy, and assumes these 21 | responsibilities: 22 | 23 | Remembering which `ICommand`s 24 | are intended to handle which `INotifications`. 25 | 26 | Registering itself as an `IObserver` with 27 | the `View` for each `INotification` 28 | that it has an `ICommand` mapping for. 29 | 30 | Creating a new instance of the proper `ICommand` 31 | to handle a given `INotification` when notified by the `View`. 32 | 33 | Calling the `ICommand`'s `execute` 34 | method, passing in the `INotification`. 35 | 36 | Your application must register `ICommands` with the 37 | Controller. 38 | 39 | The simplest way is to subclass `Facade`, 40 | and use its `initialize_controller` method to add your 41 | registrations. 42 | 43 | See Also 44 | -------- 45 | :class:`.View` 46 | :class:`puremvc.patterns.observer.Observer` 47 | :class:`puremvc.patterns.observer.Notification` 48 | :class:`puremvc.patterns.command.SimpleCommand` 49 | :class:`puremvc.patterns.command.MacroCommand` 50 | """ 51 | instanceMap: Dict[str, IController] = dict() 52 | instanceMapLock: threading.Lock = threading.Lock() 53 | 54 | """MULTITON_MSG (str): Multiton error message""" 55 | MULTITON_MSG = "Controller multiton instance for this key is already constructed!" 56 | 57 | def __init__(self, key: str) -> None: 58 | """ 59 | This `IController` implementation is a Multiton, so you should not 60 | call the constructor directly, but instead call the static Factory 61 | method, passing the unique key for this instance 62 | `Controller.get_instance(multitonKey, lambda k: Controller(k))` 63 | 64 | :param key: The unique key identifier for the Controller instance. 65 | :type key: str 66 | :raises Exception: If an instance with the given `key` already exists in the `instanceMap`. 67 | """ 68 | if Controller.instanceMap.get(key) is not None: 69 | raise Exception(Controller.MULTITON_MSG) 70 | self.multitonKey: str = key 71 | Controller.instanceMap[key] = self 72 | self.commandMap: Dict[str, Callable[[], ICommand]] = dict() 73 | self.commandMapLock: threading.Lock = threading.Lock() 74 | self.view: Optional[IView] = None 75 | self.initialize_controller() 76 | 77 | def initialize_controller(self) -> None: 78 | """ 79 | Initialize the Multiton `Controller` instance. 80 | 81 | Called automatically by the constructor. 82 | 83 | Note that if you are using a subclass of `View` in your application, 84 | you should also subclass `Controller` and override the 85 | `initialize_controller` method in the following way:: 86 | 87 | def initialize_controller(self): 88 | self.view = MyView.get_instance(self.multitonKey, lambda: key: MyView(key)) 89 | 90 | :return: None 91 | """ 92 | self.view = View.get_instance(self.multitonKey, lambda key: View(key)) 93 | 94 | @classmethod 95 | def get_instance(cls, key: str, factory: Callable[[str], IController]) -> Optional[IController]: 96 | """ 97 | `Controller` Multiton Factory method. 98 | 99 | :param key: The key used to identify the instance. 100 | :type key: str 101 | :param factory: A factory function that creates a new instance of IController based on the provided key. 102 | :type factory: Callable[[str], IController] 103 | :return: The instance of IController associated with the given key. 104 | :rtype: Optional[IController] 105 | """ 106 | with cls.instanceMapLock: 107 | if key not in cls.instanceMap: 108 | cls.instanceMap[key] = factory(key) 109 | return cls.instanceMap.get(key) 110 | 111 | def register_command(self, notification_name: str, factory: Callable[[], ICommand]) -> None: 112 | """ 113 | Register a particular `ICommand` class as the handler for a particular 114 | `INotification`. 115 | 116 | If an `ICommand` has already been registered to 117 | handle `INotification`s with this name, it is no longer 118 | used, the new `ICommand` is used instead. 119 | 120 | The Observer for the new ICommand is only created if this is the 121 | first time an ICommand has been registered for this Notification name. 122 | 123 | :param notification_name: The name of the notification. 124 | :param factory: Callable that returns an instance of ICommand. 125 | :return: None. 126 | """ 127 | with self.commandMapLock: 128 | if self.commandMap.get(notification_name) is None: 129 | if self.view: 130 | self.view.register_observer(notification_name, Observer(self.execute_command, self)) 131 | self.commandMap[notification_name] = factory 132 | 133 | def execute_command(self, notification: INotification) -> None: 134 | """ 135 | Executes the specified command based on the given notification. 136 | 137 | :param notification: The notification to be executed. 138 | :type notification: INotification 139 | :return: None 140 | """ 141 | with self.commandMapLock: 142 | factory = self.commandMap.get(notification.name) 143 | if factory is None: return 144 | 145 | command = factory() 146 | command.initialize_notifier(self.multitonKey) 147 | command.execute(notification) 148 | 149 | def has_command(self, notification_name: str) -> bool: 150 | """ 151 | Check if a Command is registered for a given Notification 152 | 153 | :param notification_name: The name of the notification to check in the `commandMap`. 154 | :type notification_name: str 155 | :return: True if the `notification_name` exists in the `commandMap`, False otherwise. 156 | :rtype: bool 157 | """ 158 | with self.commandMapLock: 159 | return self.commandMap.get(notification_name) is not None 160 | 161 | def remove_command(self, notification_name: str) -> None: 162 | """ 163 | Remove a previously registered `ICommand` to `INotification` mapping. 164 | 165 | :param notification_name: The name of the notification associated with the command to be removed. 166 | :type notification_name: str 167 | :return: None 168 | """ 169 | with self.commandMapLock: 170 | if notification_name in self.commandMap: 171 | if self.view: 172 | self.view.remove_observer(notification_name, self) 173 | del self.commandMap[notification_name] 174 | 175 | @classmethod 176 | def remove_controller(cls, key: str) -> None: 177 | """ 178 | Remove an IController instance 179 | 180 | :param key: The key to identify the controller instance to be removed. 181 | :type key: str 182 | :return: None 183 | """ 184 | with cls.instanceMapLock: 185 | del cls.instanceMap[key] 186 | -------------------------------------------------------------------------------- /src/puremvc/core/Model.py: -------------------------------------------------------------------------------- 1 | # Model.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import threading 8 | from typing import Callable, Dict, Optional 9 | 10 | from puremvc.interfaces import IModel, IProxy 11 | 12 | 13 | class Model(IModel): 14 | """ 15 | A Multiton `IModel` implementation. 16 | 17 | In PureMVC, the `Model` class provides access to model objects (Proxies) 18 | by named lookup. 19 | 20 | The `Model` assumes these responsibilities: 21 | 22 | - Maintain a cache of `IProxy` instances. 23 | - Provide methods for registering, retrieving, and removing `IProxy` instances. 24 | 25 | Your application must register `IProxy` instances with the `Model`. 26 | Typically, you use an `ICommand` to create and register `IProxy` 27 | instances once the `Facade` has initialized the Core actors. 28 | 29 | See Also 30 | -------- 31 | :class:`puremvc.patterns.proxy.Proxy` 32 | :class:`puremvc.interfaces.IProxy` 33 | """ 34 | instanceMap: Dict[str, IModel] = dict() 35 | instanceMapLock: threading.Lock = threading.Lock() 36 | 37 | """MULTITON_MSG (str): Multiton error message""" 38 | MULTITON_MSG = "Model multiton instance for this key is already constructed!" 39 | 40 | def __init__(self, key: str) -> None: 41 | """ 42 | Constructor. 43 | 44 | This IModel implementation is a Multiton, 45 | so you should not call the constructor 46 | directly, but instead call the static Multiton 47 | Factory method Model.get_instance(multiton_key) 48 | 49 | :param key: A unique key for this instance of the Model. 50 | :raises Exception: If an instance with the given `key` already exists in the `instanceMap`. 51 | :type key: str 52 | """ 53 | if Model.instanceMap.get(key) is not None: 54 | raise Exception(Model.MULTITON_MSG) 55 | self.multitonKey: str = key 56 | Model.instanceMap[key] = self 57 | self.proxyMap: Dict[str, IProxy] = dict() 58 | self.proxyMapLock: threading.Lock = threading.Lock() 59 | self.initialize_model() 60 | 61 | def initialize_model(self) -> None: 62 | """ 63 | Initialize the `Model` instance. 64 | 65 | Called automatically by the constructor, this is your opportunity to 66 | initialize the Multiton instance in your subclass without overriding 67 | the constructor. 68 | 69 | :return: None 70 | """ 71 | return 72 | 73 | @classmethod 74 | def get_instance(cls, key: str, factory: Callable[[str], IModel]) -> Optional[IModel]: 75 | """ 76 | Multiton Factory method. 77 | 78 | :param key: A string representing the key used to retrieve the instance. 79 | :type key: str 80 | :param factory: A factory function used to create new instances of `IModel`. 81 | :type factory: Callable[[str], IModel] 82 | :return: An instance of `IModel` associated with the given key. 83 | :rtype: Optional[IModel] 84 | """ 85 | with cls.instanceMapLock: 86 | if key not in cls.instanceMap: 87 | cls.instanceMap[key] = factory(key) 88 | return cls.instanceMap.get(key) 89 | 90 | def register_proxy(self, proxy: IProxy) -> None: 91 | """ 92 | Register an `IProxy` with the `Model`. 93 | 94 | :param proxy: An `IProxy` to be held by the `Model`. 95 | :type proxy: IProxy 96 | :return: None 97 | """ 98 | proxy.initialize_notifier(self.multitonKey) 99 | with self.proxyMapLock: 100 | self.proxyMap[proxy.proxy_name] = proxy 101 | proxy.on_register() 102 | 103 | def retrieve_proxy(self, proxy_name: str) -> Optional[IProxy]: 104 | """ 105 | Retrieve an `IProxy` from the `Model`. 106 | 107 | :param proxy_name: The name of the proxy. 108 | :type proxy_name: str 109 | :return: the `IProxy` instance previously registered with the given `proxyName`. 110 | :rtype: Optional[IProxy] 111 | """ 112 | with self.proxyMapLock: 113 | return self.proxyMap.get(proxy_name) 114 | 115 | def has_proxy(self, proxy_name: str) -> bool: 116 | """ 117 | Check if a Proxy is registered 118 | 119 | :param proxy_name: A string representing the name of the proxy to check. 120 | :type proxy_name: str 121 | :return: Returns True if the proxy exists in the proxy map, False otherwise. 122 | :rtype: bool 123 | """ 124 | with self.proxyMapLock: 125 | return self.proxyMap.get(proxy_name) is not None 126 | 127 | def remove_proxy(self, proxy_name: str) -> Optional[IProxy]: 128 | """ 129 | Remove an `IProxy` from the `Model`. 130 | 131 | :param proxy_name: The name of the `IProxy` to remove. 132 | :type proxy_name: str 133 | :return: the `IProxy` that was removed from the `Model` 134 | :rtype: Optional[IProxy] 135 | """ 136 | with self.proxyMapLock: 137 | proxy = self.proxyMap.get(proxy_name) 138 | if proxy: 139 | del self.proxyMap[proxy_name] 140 | if proxy: 141 | proxy.on_remove() 142 | return proxy 143 | 144 | @classmethod 145 | def remove_model(cls, key: str) -> None: 146 | """ 147 | Remove an IModel instance 148 | 149 | :param key: multiton_key of IModel instance to remove 150 | :type key: str 151 | :return: None 152 | """ 153 | with cls.instanceMapLock: 154 | del cls.instanceMap[key] 155 | -------------------------------------------------------------------------------- /src/puremvc/core/__init__.py: -------------------------------------------------------------------------------- 1 | from .Controller import Controller 2 | from .Model import Model 3 | from .View import View 4 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/ICommand.py: -------------------------------------------------------------------------------- 1 | # ICommand.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import abstractmethod 8 | 9 | from .INotification import INotification 10 | from .INotifier import INotifier 11 | 12 | 13 | class ICommand(INotifier): 14 | """ 15 | The interface definition for a PureMVC Command 16 | 17 | See Also 18 | -------- 19 | :class:`puremvc.interfaces.INotification` 20 | """ 21 | 22 | @abstractmethod 23 | def execute(self, notification: INotification) -> None: 24 | """ 25 | Execute the `ICommand`'s logic to handle a given `INotification`. 26 | 27 | :param notification: An `INotification` to handle. 28 | :type notification: INotification 29 | :return: None 30 | """ 31 | pass 32 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IController.py: -------------------------------------------------------------------------------- 1 | # IController.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Callable 9 | 10 | from .ICommand import ICommand 11 | from .INotification import INotification 12 | 13 | 14 | class IController(ABC): 15 | """ 16 | The interface definition for a PureMVC Controller. 17 | 18 | In PureMVC, an `IController` implementor follows the 'Command and Controller' strategy, and 19 | assumes these responsibilities: 20 | 21 | Remembering which `ICommand`s are intended to handle which `INotifications`. 22 | 23 | Registering itself as an `IObserver` with the `View` for each `INotification` 24 | that it has an `ICommand` mapping for. 25 | 26 | Creating a new instance of the proper `ICommand` to handle a given `INotification` when notified by the `View`. 27 | 28 | Calling the `ICommand`'s `execute` method, passing in the `INotification`. 29 | 30 | See Also 31 | -------- 32 | :class:`puremvc.interfaces.INotification` 33 | :class:`puremvc.interfaces.ICommand` 34 | """ 35 | 36 | @abstractmethod 37 | def register_command(self, notification_name: str, factory: Callable[[], ICommand]) -> None: 38 | """ 39 | Register a particular `ICommand` class as the handler for a particular `INotification`. 40 | 41 | :param notification_name: The name of the `INotification` 42 | :type notification_name: str 43 | :param factory: A factory function that returns an instance of ICommand. 44 | :type factory: Callable[[], ICommand] 45 | :return: None 46 | """ 47 | pass 48 | 49 | @abstractmethod 50 | def execute_command(self, notification: INotification) -> None: 51 | """ 52 | Execute the `ICommand` previously registered as the handler for 53 | `INotification` with the given notification name. 54 | 55 | :param notification: The `INotification` to execute the associated `ICommand` for 56 | :type notification: INotification 57 | :return: None 58 | """ 59 | pass 60 | 61 | @abstractmethod 62 | def has_command(self, notification_name: str) -> bool: 63 | """ 64 | Check if a Command is registered for a given Notification. 65 | 66 | :param notification_name: The name of the `INotification` 67 | :type notification_name: str 68 | :return: True if a command is registered for the notification_name, False otherwise. 69 | :rtype: bool 70 | """ 71 | pass 72 | 73 | @abstractmethod 74 | def remove_command(self, notification_name: str) -> None: 75 | """ 76 | Remove a previously registered `ICommand` to `INotification` mapping. 77 | 78 | :param notification_name: The name of the `INotification` to remove the `ICommand` mapping for 79 | :type notification_name: str 80 | :return: None 81 | """ 82 | pass 83 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IFacade.py: -------------------------------------------------------------------------------- 1 | # IFacade.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Callable, Optional 9 | 10 | from .ICommand import ICommand 11 | from .IMediator import IMediator 12 | from .INotification import INotification 13 | from .INotifier import INotifier 14 | from .IProxy import IProxy 15 | 16 | 17 | class IFacade(INotifier, ABC): 18 | """ 19 | The interface definition for a PureMVC Facade. 20 | 21 | The Facade Pattern suggests providing a single class to act as a central point of communication 22 | for a subsystem. 23 | 24 | In PureMVC, the Facade acts as an interface between the core MVC actors (Model, View, Controller) and 25 | the rest of your application. 26 | 27 | :class:`puremvc.interfaces.IModel` 28 | :class:`puremvc.interfaces.IView` 29 | :class:`puremvc.interfaces.IController` 30 | :class:`puremvc.interfaces.ICommand` 31 | :class:`puremvc.interfaces.INotification` 32 | """ 33 | 34 | @abstractmethod 35 | def register_proxy(self, proxy: IProxy) -> None: 36 | """ 37 | Register a `Proxy` with the `Model` by name. 38 | 39 | :param proxy: The `IProxy` to be registered with the `Model`. 40 | :type proxy: IProxy 41 | :return: None 42 | """ 43 | pass 44 | 45 | @abstractmethod 46 | def retrieve_proxy(self, proxy_name: str) -> Optional[IProxy]: 47 | """ 48 | Retrieve a `IProxy` from the `Model` by name. 49 | 50 | :param proxy_name: The name of the `IProxy` instance to be retrieved. 51 | :type proxy_name: str 52 | :return: the `IProxy` previously registered by `proxyName` with the `Model`. 53 | """ 54 | pass 55 | 56 | @abstractmethod 57 | def remove_proxy(self, proxy_name: str) -> Optional[IProxy]: 58 | """ 59 | Remove an `IProxy` instance from the `Model` by name. 60 | 61 | :param proxy_name: The `IProxy` to remove from the `Model`. 62 | :type proxy_name: str 63 | :return: the `IProxy` that was removed from the `Model` 64 | :rtype: IProxy 65 | """ 66 | pass 67 | 68 | @abstractmethod 69 | def has_proxy(self, proxy_name: str) -> bool: 70 | """ 71 | Check if a Proxy is registered 72 | 73 | :param proxy_name: The name of the proxy to check. 74 | :type proxy_name: str 75 | :return: True if the proxy is currently registered, False otherwise. 76 | :rtype: bool 77 | """ 78 | pass 79 | 80 | @abstractmethod 81 | def register_command(self, notification_name: str, factory: Callable[[], ICommand]) -> None: 82 | """ 83 | Register an `ICommand` with the `Controller`. 84 | 85 | :param notification_name: The name of the `INotification` to associate the `ICommand` with. 86 | :type notification_name: str 87 | :param factory: A callable factory function that creates an instance of `ICommand`. 88 | :type factory: Callable[[], ICommand] 89 | :return: None 90 | """ 91 | pass 92 | 93 | @abstractmethod 94 | def has_command(self, notification_name: str) -> bool: 95 | """ 96 | Check if a Command is registered for a given `Notification`. 97 | 98 | :param notification_name: The name of the notification to check. 99 | :type notification_name: str 100 | :return: True if a command exists for the given `notification_name`, False otherwise. 101 | """ 102 | pass 103 | 104 | @abstractmethod 105 | def remove_command(self, notification_name: str) -> None: 106 | """ 107 | Remove a previously registered `ICommand` to `INotification` mapping from the Controller. 108 | 109 | :param notification_name: The name of the `INotification` to remove the `ICommand` mapping for 110 | :type notification_name: str 111 | :return: None 112 | """ 113 | pass 114 | 115 | @abstractmethod 116 | def register_mediator(self, mediator: IMediator) -> None: 117 | """ 118 | Register an `IMediator` instance with the `View`. 119 | 120 | :param mediator: A reference to the `IMediator` instance 121 | :type mediator: IMediator 122 | :return: None 123 | """ 124 | pass 125 | 126 | @abstractmethod 127 | def retrieve_mediator(self, mediator_name: str) -> Optional[IMediator]: 128 | """ 129 | Retrieve an `IMediator` instance from the `View`. 130 | 131 | :param mediator_name: The name of the `IMediator` instance to retrieve 132 | :type mediator_name: str 133 | :return: The mediator object found, of type IMediator. 134 | """ 135 | pass 136 | 137 | @abstractmethod 138 | def has_mediator(self, mediator_name: str) -> bool: 139 | """ 140 | Check if a Mediator is registered or not 141 | 142 | :param mediator_name: The name of the mediator to check for. 143 | :type mediator_name: str 144 | :return: True if the mediator exists, False otherwise. 145 | """ 146 | pass 147 | 148 | @abstractmethod 149 | def remove_mediator(self, mediator_name: str) -> Optional[IMediator]: 150 | """ 151 | Remove a `IMediator` instance from the `View`. 152 | 153 | :param mediator_name: name of the `IMediator` instance to be removed. 154 | :type mediator_name: str 155 | :return: The `IMediator` instance previously registered with the given `mediator_name`. 156 | """ 157 | pass 158 | 159 | @abstractmethod 160 | def notify_observers(self, notification: INotification) -> None: 161 | """ 162 | Notify `Observer` 163 | 164 | :param notification: The `INotification` to have the `View` notify `Observers` of. 165 | :type notification: INotification 166 | :return: None 167 | """ 168 | pass 169 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IMediator.py: -------------------------------------------------------------------------------- 1 | # IMediator.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import abstractmethod 8 | from typing import Any, List 9 | 10 | from .INotification import INotification 11 | from .INotifier import INotifier 12 | 13 | 14 | class IMediator(INotifier): 15 | """ 16 | The base interface for all Mediator classes. 17 | 18 | In PureMVC, `IMediator` implementors assume these responsibilities: 19 | 20 | Implement a common method which returns a list of all `INotification` 21 | the `IMediator` has interest in implementing a notification callback method. 22 | Implement methods that are called when the IMediator is registered or removed from the View. 23 | 24 | Additionally, `IMediator` typically: 25 | 26 | Act as an intermediary between one or more view components such as text boxes or 27 | list controls, maintaining references and coordinating their behavior. 28 | 29 | In Flash-based apps, this is often the place where event listeners are 30 | added to view components, and their handlers implemented. 31 | 32 | Respond to and generate `INotifications`, interacting with of 33 | the rest of the PureMVC app. 34 | 35 | When an `IMediator` is registered with the `IView`, 36 | the `IView` will call the `IMediator`'s 37 | `list_notification_interests` method. The `IMediator` will 38 | return an `Array` of `INotification` names which 39 | it wishes to be notified about. 40 | 41 | The `IView` will then create an `Observer` object 42 | encapsulating that `IMediator`'s (`handle_notification`) method 43 | and register it as an Observer for each `INotification` name returned by 44 | `list_notification_interests`. 45 | 46 | See Also 47 | -------- 48 | :class:`puremvc.interfaces.INotification` 49 | """ 50 | 51 | @property 52 | @abstractmethod 53 | def mediator_name(self) -> str: 54 | """ 55 | Get the `IMediator` instance name. 56 | 57 | :return: The `IMediator` instance name 58 | """ 59 | pass 60 | 61 | @property 62 | @abstractmethod 63 | def view_component(self) -> Any: 64 | """ 65 | Get the `IMediator`'s view component. 66 | 67 | :return: The view component. 68 | :rtype: Any 69 | """ 70 | pass 71 | 72 | @view_component.setter 73 | def view_component(self, value: Any) -> None: 74 | """ 75 | Set the `IMediator`'s view component. 76 | 77 | :param value: The view component 78 | :type value: Any 79 | :return: None 80 | """ 81 | pass 82 | 83 | @abstractmethod 84 | def list_notification_interests(self) -> List[str]: 85 | """ 86 | List `INotification` interests. 87 | 88 | :return: A list containing strings representing the notification interests. 89 | :rtype: [str] 90 | """ 91 | pass 92 | 93 | @abstractmethod 94 | def handle_notification(self, notification: INotification) -> None: 95 | """ 96 | Handle an `INotification`. 97 | 98 | :param notification: The `INotification` to be handled 99 | :type notification: INotification 100 | :return: None 101 | """ 102 | pass 103 | 104 | @abstractmethod 105 | def on_register(self) -> None: 106 | """ 107 | Called by the View when the Mediator is registered 108 | :return: None 109 | """ 110 | pass 111 | 112 | @abstractmethod 113 | def on_remove(self) -> None: 114 | """ 115 | Called by the View when the Mediator is removed 116 | :return: None 117 | """ 118 | pass 119 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IModel.py: -------------------------------------------------------------------------------- 1 | # IModel.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Optional 9 | 10 | from .IProxy import IProxy 11 | 12 | 13 | class IModel(ABC): 14 | """ 15 | The interface definition for a PureMVC Model. 16 | 17 | In PureMVC, `IModel` implementors provide 18 | access to `IProxy` objects by named look up. 19 | 20 | An `IModel` assumes these responsibilities: 21 | 22 | Maintain a cache of `IProxy` instances 23 | Provide methods for registering, retrieving, and removing `IProxy` instances 24 | """ 25 | 26 | @abstractmethod 27 | def register_proxy(self, proxy: IProxy) -> None: 28 | """ 29 | Register an `IProxy` instance with the `Model`. 30 | 31 | :param proxy: An object reference to be held by the `Model`. 32 | :type proxy: IProxy 33 | :return: None 34 | """ 35 | pass 36 | 37 | @abstractmethod 38 | def retrieve_proxy(self, proxy_name: str) -> Optional[IProxy]: 39 | """ 40 | Retrieve an `IProxy` instance from the Model. 41 | 42 | :param proxy_name: The name of the proxy to retrieve. 43 | :type proxy_name: str 44 | :return: The `IProxy` instance previously registered with the given `proxy_name`. 45 | :rtype: IProxy 46 | """ 47 | pass 48 | 49 | @abstractmethod 50 | def remove_proxy(self, proxy_name: str) -> Optional[IProxy]: 51 | """ 52 | Remove an `IProxy` instance from the Model. 53 | 54 | :param proxy_name: The name of the proxy to remove. 55 | :type proxy_name: str 56 | :return: The `IProxy` instance that was removed from the Model. 57 | :rtype: IProxy 58 | """ 59 | pass 60 | 61 | @abstractmethod 62 | def has_proxy(self, proxy_name: str) -> bool: 63 | """ 64 | Check if a proxy with the given name is registered. 65 | 66 | :param proxy_name: The name of the proxy to check. 67 | :type proxy_name: str 68 | :return: True if the proxy is registered, False otherwise. 69 | :rtype: bool 70 | """ 71 | pass 72 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/INotification.py: -------------------------------------------------------------------------------- 1 | # INotification.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Any 9 | 10 | 11 | class INotification(ABC): 12 | """ 13 | The interface definition for a PureMVC Notification. 14 | 15 | PureMVC does not rely upon underlying event models such 16 | as the one provided with Flash, and ActionScript 3 does 17 | not have an inherent event model. 18 | 19 | The Observer Pattern as implemented within PureMVC exists 20 | to support event-driven communication between the 21 | application and the actors of the MVC triad. 22 | 23 | Notifications are not meant to be a replacement for Events 24 | in Flex/Flash/AIR. Generally, `IMediator` implementors 25 | place event listeners on their view components, which they 26 | then handle in the usual way. This may lead to the broadcast of `Notification` to 27 | trigger `ICommand` or to communicate with other `IMediator`, `IProxy` and `ICommand` 28 | instances communicate with each other and `IMediator` by broadcasting `INotification`. 29 | 30 | A key difference between Flash `Event` and PureMVC 31 | `Notification` is that `Event` follows the 32 | 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 33 | until some parent component handles the `Event`, while 34 | PureMVC `Notification` follows a 'Publish/Subscribe' 35 | pattern. PureMVC classes need not be related to each other in a 36 | parent/child relationship to communicate with one another 37 | using `Notification`. 38 | 39 | See Also 40 | -------- 41 | :class:`puremvc.interfaces.IView` 42 | :class:`puremvc.interfaces.IObserver` 43 | """ 44 | 45 | @property 46 | @abstractmethod 47 | def name(self) -> str: 48 | """ 49 | Get the name of the `INotification` instance. 50 | No setter, it should be set by constructor only 51 | 52 | :return: The name of the object. 53 | """ 54 | pass 55 | 56 | @property 57 | @abstractmethod 58 | def body(self) -> Any: 59 | """ 60 | Get the body of the `INotification` instance 61 | 62 | :return: The body of the method. 63 | :rtype: Any 64 | """ 65 | pass 66 | 67 | @body.setter 68 | @abstractmethod 69 | def body(self, body: Any) -> None: 70 | """ 71 | Set the body of the `INotification` instance 72 | 73 | :param body: The new body value to set for the method 74 | :type body: Any 75 | :return: None 76 | """ 77 | pass 78 | 79 | @property 80 | @abstractmethod 81 | def type(self) -> str: 82 | """ 83 | Get the type of the `INotification` instance 84 | 85 | :return: The type of the object. 86 | :rtype: str 87 | """ 88 | pass 89 | 90 | @type.setter 91 | @abstractmethod 92 | def type(self, _type: str) -> None: 93 | """ 94 | Set the type of the `INotification` instance 95 | 96 | :param _type: The type of the note. 97 | :type _type: str 98 | :return: None 99 | """ 100 | pass 101 | 102 | @abstractmethod 103 | def __repr__(self) -> str: 104 | """ 105 | Get the string representation of the `INotification` instance 106 | 107 | :return: The string representation of the object. 108 | :rtype: str 109 | """ 110 | pass 111 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/INotifier.py: -------------------------------------------------------------------------------- 1 | # INotifier.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import abstractmethod, ABC 8 | from typing import Any, Optional 9 | 10 | 11 | class INotifier(ABC): 12 | """ 13 | The interface definition for a PureMVC Notifier. 14 | 15 | `MacroCommand, Command, Mediator` and `Proxy` 16 | all have a need to send `Notifications`. 17 | 18 | The `INotifier` interface provides a common method called 19 | `send_notification` that relieves implementation code of 20 | the necessity to actually construct `Notifications`. 21 | 22 | The `Notifier` class, which all the above-mentioned classes 23 | extend, also provides an initialized reference to the `Facade` 24 | Singleton, which is required for the convenience method 25 | for sending `Notifications`, but also eases implementation as these 26 | classes have frequent `Facade` interactions and usually require 27 | access to the facade anyway. 28 | 29 | See Also 30 | -------- 31 | :class:`puremvc.interfaces.IFacade` 32 | :class:`puremvc.interfaces.INotification` 33 | """ 34 | 35 | @abstractmethod 36 | def send_notification(self, notification_name: str, body: Any = None, type: Optional[str] = None) -> None: 37 | """ 38 | Send a `INotification`. 39 | 40 | Convenience method to prevent having to construct new notification 41 | instances in our implementation code. 42 | 43 | :param notification_name: The name of the notification to send 44 | :type notification_name: str 45 | :param body: the body of the notification (optional) 46 | :type body: Any 47 | :param type: the type of the notification (optional) 48 | :type type: str 49 | :return: None 50 | """ 51 | pass 52 | 53 | @abstractmethod 54 | def initialize_notifier(self, key: str) -> None: 55 | """ 56 | Initialise this `INotifier` instance. 57 | 58 | This is how a `Notifier` gets its `multiton_key`. Calls to `send_notification` 59 | or to access the facade will fail until after this method has been 60 | called. 61 | 62 | :param key: The `multiton_key` for this `INotifier` to use 63 | :type key: str 64 | :return: None 65 | """ 66 | pass 67 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IObserver.py: -------------------------------------------------------------------------------- 1 | # IObserver.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Any, Callable 9 | 10 | from .INotification import INotification 11 | 12 | 13 | class IObserver(ABC): 14 | """ 15 | The interface definition for a PureMVC Observer. 16 | 17 | In PureMVC, `IObserver` implementors assume these responsibilities: 18 | 19 | Encapsulate the notification (callback) method of the interested object. 20 | 21 | Encapsulate the notification context of the interested object. 22 | 23 | Provide methods for setting the interested object notification method and context. 24 | 25 | Provide a method for notifying the interested object. 26 | 27 | PureMVC does not rely upon underlying event 28 | models such as the one provided with Flash, 29 | and ActionScript 3 does not have an inherent 30 | event model. 31 | 32 | The Observer Pattern as implemented within 33 | PureMVC exists to support event driven communication 34 | between the application and the actors of the 35 | MVC triad. 36 | 37 | An Observer is an object that encapsulates information 38 | about an interested object with a notification method that 39 | should be called when an `INotification` is broadcast. The Observer then 40 | acts as a proxy for notifying the interested object. 41 | 42 | Observers can receive `Notification`s by having their 43 | `notify_observer` method invoked, passing 44 | in an object implementing the `INotification` interface, such 45 | as a subclass of `Notification`. 46 | 47 | See Also 48 | -------- 49 | :class:`puremvc.interfaces.IView` 50 | :class:`puremvc.interfaces.INotification` 51 | 52 | """ 53 | 54 | @property 55 | @abstractmethod 56 | def notify_method(self) -> Callable[[INotification], None]: 57 | """ 58 | Set the notification method. 59 | 60 | The notification method should take one parameter of type `INotification` 61 | 62 | :return: The notification (callback) method of the interested object 63 | :rtype: Callable[[INotification], None] 64 | """ 65 | pass 66 | 67 | @notify_method.setter 68 | @abstractmethod 69 | def notify_method(self, value: Callable[[INotification], None]) -> None: 70 | """ 71 | Set the notification context. 72 | 73 | :param value: The notification context (self) of the interested 74 | :type value: Callable[[INotification, None] 75 | """ 76 | pass 77 | 78 | @property 79 | @abstractmethod 80 | def notify_context(self) -> Any: 81 | """ 82 | Get the notify_context. 83 | 84 | :return: notify context 85 | :rtype: Any 86 | """ 87 | pass 88 | 89 | @notify_context.setter 90 | @abstractmethod 91 | def notify_context(self, value: Any) -> None: 92 | """ 93 | Sets the value of the `notify_context` attribute. 94 | 95 | :param value: The value to be set for the `notify_context` attribute. 96 | :type value: Any 97 | :return: None 98 | """ 99 | pass 100 | 101 | @abstractmethod 102 | def notify_observer(self, notification: INotification) -> None: 103 | """ 104 | Notify the interested object. 105 | 106 | :param notification: The `INotification` to pass to the interested object's notification method 107 | :type notification: INotification 108 | :return: None 109 | """ 110 | pass 111 | 112 | @abstractmethod 113 | def compare_notify_context(self, obj: Any) -> bool: 114 | """ 115 | Compare the given object to the notification context object. 116 | 117 | :param obj: The object to compare. 118 | :type obj: Any 119 | :return: boolean indicating if the notification context and the object are the same. 120 | """ 121 | pass 122 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IProxy.py: -------------------------------------------------------------------------------- 1 | # IProxy.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import abstractmethod 8 | from typing import Any 9 | 10 | from .INotifier import INotifier 11 | 12 | 13 | class IProxy(INotifier): 14 | """ 15 | The interface definition for a PureMVC Proxy. 16 | 17 | In PureMVC, 'IProxy' implementors assume these responsibilities:

18 | 19 | Implement a common method which returns the name of the Proxy. 20 | Provide methods for setting and getting the data object. 21 | 22 | Additionally, 'IProxy's typically: 23 | 24 | Maintain references to one or more pieces of model data. 25 | Provide methods for manipulating that data. 26 | Generate 'INotifications' when their model data changes. 27 | Expose their name as a 'public static const' called 'NAME', 28 | if they are not instantiated multiple times. 29 | Encapsulate interaction with local or remote services used to fetch and persist model data. 30 | """ 31 | 32 | @property 33 | @abstractmethod 34 | def proxy_name(self) -> str: 35 | """ 36 | Get the Proxy name 37 | 38 | :return: The name of the proxy as a string. 39 | :rtype: str 40 | """ 41 | pass 42 | 43 | @property 44 | @abstractmethod 45 | def data(self) -> Any: 46 | """ 47 | Get the data object 48 | 49 | :return: The data of the method. 50 | :rtype: Any 51 | """ 52 | pass 53 | 54 | @data.setter 55 | def data(self, value: Any) -> None: 56 | """ 57 | Get the data object 58 | 59 | :param value: The value to be set for the `data` attribute. 60 | :type value: Any 61 | :return: None 62 | """ 63 | pass 64 | 65 | @abstractmethod 66 | def on_register(self) -> None: 67 | """ 68 | Called by the Model when the Proxy is registered. 69 | :return: None 70 | """ 71 | pass 72 | 73 | @abstractmethod 74 | def on_remove(self) -> None: 75 | """ 76 | Called by the Model when the Proxy is removed. 77 | :return: None 78 | """ 79 | pass 80 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/IView.py: -------------------------------------------------------------------------------- 1 | # IView.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Any, Optional 9 | 10 | from .IMediator import IMediator 11 | from .INotification import INotification 12 | from .IObserver import IObserver 13 | 14 | 15 | class IView(ABC): 16 | """ 17 | The interface definition for a PureMVC View. 18 | 19 | In PureMVC, `IView` implementors assume these responsibilities: 20 | 21 | In PureMVC, the `View` class assumes these responsibilities: 22 | 23 | Maintain a cache of `IMediator` instances. 24 | Provide methods for registering, retrieving, and removing `IMediators`. 25 | Managing the observer lists for each `INotification` in the application. 26 | Providing a method for attaching `IObservers` to an `INotification`'s observer list. 27 | Providing a method for broadcasting an `INotification`. 28 | Notifying the `IObservers` of a given `INotification` when it broadcast. 29 | 30 | See Also 31 | -------- 32 | :class:`puremvc.interfaces.IMediator` 33 | :class:`puremvc.interfaces.IObserver` 34 | :class:`puremvc.interfaces.INotification` 35 | """ 36 | 37 | @abstractmethod 38 | def register_observer(self, notification_name: str, observer: IObserver) -> None: 39 | """ 40 | Register an `IObserver` to be notified of `INotifications` with a 41 | given name. 42 | 43 | :param notification_name: The name of the `INotifications` to notify this `IObserver` of 44 | :type notification_name: str 45 | :param observer: The `IObserver` to register 46 | :type observer: IObserver 47 | :return: None 48 | """ 49 | pass 50 | 51 | @abstractmethod 52 | def notify_observers(self, notification: INotification) -> None: 53 | """ 54 | Notify the `IObservers` for a particular `INotification`. 55 | 56 | All previously attached `IObservers` for this `INotification`'s 57 | list are notified and are passed a reference to the `INotification` in 58 | the order in which they were registered. 59 | 60 | :param notification: The `INotification` to notify `IObservers` of. 61 | :type notification: INotification 62 | :return: None 63 | """ 64 | pass 65 | 66 | @abstractmethod 67 | def remove_observer(self, notification_name: str, notify_context: Any) -> None: 68 | """ 69 | Remove a group of observers from the observer list for a given Notification name. 70 | 71 | :param notification_name: Which observer list to remove from 72 | :type notification_name: str 73 | :param notify_context: Removed the observers with this object as their notify_context 74 | :type notify_context: Any 75 | :return: None 76 | """ 77 | pass 78 | 79 | @abstractmethod 80 | def register_mediator(self, mediator: IMediator) -> None: 81 | """ 82 | Register an `IMediator` instance with the `View`. 83 | 84 | Registers the `IMediator` so that it can be retrieved by name, 85 | and further interrogates the `IMediator` for its 86 | `INotification` interests. 87 | 88 | If the `IMediator` returns any `INotification` 89 | names to be notified about, an `Observer` is created encapsulating 90 | the `IMediator` instance's `handleNotification` method 91 | and registering it as an `Observer` for all `INotifications` the 92 | `IMediator` is interested in. 93 | 94 | :param mediator: A reference to the `IMediator` instance 95 | :type mediator: IMediator 96 | :return: None 97 | """ 98 | pass 99 | 100 | @abstractmethod 101 | def retrieve_mediator(self, mediator_name: str) -> Optional[IMediator]: 102 | """ 103 | Retrieve an `IMediator` from the `View`. 104 | 105 | :param mediator_name: The name of the `IMediator` instance to retrieve. 106 | :type mediator_name: str 107 | :return: The `IMediator` instance previously registered with the given `mediatorName`. 108 | :rtype: Optional[IMediator] 109 | """ 110 | pass 111 | 112 | @abstractmethod 113 | def has_mediator(self, mediator_name: str) -> bool: 114 | """ 115 | Check if a Mediator is registered or not. 116 | 117 | :param mediator_name: Name of the `IMediator` 118 | :type mediator_name: str 119 | :return: whether a Mediator is registered with the given `mediatorName`. 120 | :rtype: bool 121 | """ 122 | pass 123 | 124 | @abstractmethod 125 | def remove_mediator(self, mediator_name: str) -> Optional[IMediator]: 126 | """ 127 | Remove an `IMediator` from the `View`. 128 | 129 | :param mediator_name: Name of the `IMediator` instance to be removed. 130 | :type mediator_name: str 131 | :return: the `IMediator` that was removed from the `View` 132 | :rtype: Optional[IMediator] 133 | """ 134 | pass 135 | -------------------------------------------------------------------------------- /src/puremvc/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | from .IController import IController 2 | from .IModel import IModel 3 | from .IView import IView 4 | from .ICommand import ICommand 5 | from .IFacade import IFacade 6 | from .IMediator import IMediator 7 | from .INotification import INotification 8 | from .INotifier import INotifier 9 | from .IObserver import IObserver 10 | from .IProxy import IProxy 11 | -------------------------------------------------------------------------------- /src/puremvc/patterns/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PureMVC/puremvc-python-multicore-framework/5d13a5987297fe0a81744f92729944b52fc30c31/src/puremvc/patterns/__init__.py -------------------------------------------------------------------------------- /src/puremvc/patterns/command/MacroCommand.py: -------------------------------------------------------------------------------- 1 | # MacroCommand.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from typing import List, Callable 8 | 9 | from puremvc.interfaces import ICommand, INotification 10 | from puremvc.patterns.facade import Notifier 11 | 12 | 13 | class MacroCommand(Notifier, ICommand): 14 | """ 15 | A base `ICommand` implementation that executes other `ICommand`. 16 | 17 | A `MacroCommand` maintains a list of `ICommand` Class references called `SubCommands`. 18 | 19 | When `execute` is called, the `MacroCommand` 20 | instantiates and calls `execute` on each of its `SubCommand` turn. 21 | Each `SubCommand` will be passed a reference to the original 22 | `INotification` that was passed to the `MacroCommand`'s 23 | `execute` method. 24 | 25 | Unlike `SimpleCommand`, your subclass 26 | should not override `execute`, but instead, should 27 | override the `initialize_macro_command` method, 28 | calling `add_subcommand` once for each `SubCommand` 29 | to be executed. 30 | 31 | See Also 32 | -------- 33 | :class:`puremvc.core.Controller` 34 | :class:`puremvc.patterns.observer.Notification` 35 | :class:`puremvc.patterns.command.SimpleCommand` 36 | """ 37 | 38 | def __init__(self) -> None: 39 | """ 40 | MacroCommand Constructor. 41 | 42 | You should not need to define a constructor, instead, override the `initialize_macro_command` method. 43 | 44 | If your subclass does define a constructor, be sure to call `super().__init__()`. 45 | """ 46 | super().__init__() 47 | self._subcommands: List[Callable[[], ICommand]] = [] 48 | 49 | def initialize_macro_command(self) -> None: 50 | """ 51 | Initialize the `MacroCommand`. 52 | 53 | In your subclass, override this method to initialize the `MacroCommand` `SubCommand` list with `ICommand` 54 | class references like this: 55 | 56 | Initialize MyMacroCommand:: 57 | 58 | def initialize_macro_command(self): 59 | self.add_subcommand(lambda: FirstCommand()) 60 | self.add_subcommand(lambda: SecondCommand()) 61 | self.add_subcommand(lambda: ThirdCommand()) 62 | 63 | Note that `SubCommand` may be any `ICommand` implementor, 64 | `MacroCommand` or `SimpleCommands` are both acceptable. 65 | 66 | :return: None 67 | """ 68 | return 69 | 70 | def add_subcommand(self, factory: Callable[[], ICommand]) -> None: 71 | """ 72 | Add a `SubCommand`. 73 | 74 | The `SubCommands` will be called in First In/First Out (FIFO) order. 75 | 76 | :param factory: A callable object that returns an instance of ICommand. 77 | :type factory: Callable[[], ICommand] 78 | :return: None 79 | """ 80 | self._subcommands.append(factory) 81 | 82 | def execute(self, notification: INotification) -> None: 83 | """ 84 | Execute this `MacroCommand`'s `SubCommands`. 85 | 86 | The `SubCommands` will be called in First In/First Out (FIFO) 87 | order. 88 | 89 | :param notification: The `INotification` object to be passed to each`SubCommand`. 90 | :type notification: INotification 91 | :return: None 92 | """ 93 | self.initialize_macro_command() 94 | while self._subcommands: 95 | factory = self._subcommands.pop(0) 96 | command = factory() 97 | if self.multitonKey is None: raise ValueError("multitonKey must not be None") 98 | command.initialize_notifier(self.multitonKey) 99 | command.execute(notification) 100 | -------------------------------------------------------------------------------- /src/puremvc/patterns/command/SimpleCommand.py: -------------------------------------------------------------------------------- 1 | # SimpleCommand.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from puremvc.interfaces import INotification, ICommand 8 | 9 | from puremvc.patterns.facade import Notifier 10 | 11 | 12 | class SimpleCommand(Notifier, ICommand): 13 | """ 14 | A base `ICommand` implementation. 15 | 16 | Your subclass should override the `execute` 17 | method where your business logic will handle the `INotification`. 18 | 19 | See Also 20 | -------- 21 | :class:`puremvc.core.Controller` 22 | :class:`puremvc.patterns.observer.Notification` 23 | :class:`puremvc.patterns.command.MacroCommand` 24 | """ 25 | 26 | def execute(self, notification: INotification) -> None: 27 | """ 28 | Fulfill the use-case initiated by the given `INotification`. 29 | 30 | In the Command Pattern, an application use-case typically 31 | begins with some user action, which results in an `INotification` being broadcast, which 32 | is handled by business logic in the `execute` method of an `ICommand`. 33 | 34 | :param notification: The `INotification` to handle. 35 | :type notification: INotification 36 | :return: None 37 | """ 38 | return 39 | -------------------------------------------------------------------------------- /src/puremvc/patterns/command/__init__.py: -------------------------------------------------------------------------------- 1 | from .MacroCommand import MacroCommand 2 | from .SimpleCommand import SimpleCommand 3 | -------------------------------------------------------------------------------- /src/puremvc/patterns/facade/Notifier.py: -------------------------------------------------------------------------------- 1 | # Notifier.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from typing import Any, Optional 8 | 9 | from puremvc.interfaces import IFacade, INotifier 10 | from puremvc.patterns.facade.Facade import Facade 11 | 12 | 13 | class Notifier(INotifier): 14 | """ 15 | A Base `INotifier` implementation. 16 | 17 | `MacroCommand, Command, Mediator` and `Proxy` 18 | all have a need to send `Notifications`. 19 | 20 | The `INotifier` interface provides a common method called 21 | `sendNotification` that relieves implementation code of 22 | the necessity to actually construct `Notifications`. 23 | 24 | The `Notifier` class, which all the above-mentioned classes 25 | extend, provides an initialized reference to the `Facade` 26 | Multiton, which is required for the convenience method 27 | for sending `Notifications`, but also eases implementation as these 28 | classes have frequent `Facade` interactions and usually require 29 | access to the facade anyway. 30 | 31 | NOTE: In the MultiCore version of the framework, there is one caveat to 32 | notifiers, they cannot send notifications or reach the facade until they 33 | have a valid multitonKey. 34 | 35 | The multitonKey is set: 36 | 37 | - on a Command when it is executed by the Controller 38 | - on a Mediator is registered with the View 39 | - on a Proxy is registered with the Model. 40 | 41 | See Also 42 | -------- 43 | :class:`puremvc.patterns.proxy.Proxy` 44 | :class:`puremvc.patterns.facade.Facade` 45 | :class:`puremvc.patterns.mediator.Mediator` 46 | :class:`puremvc.patterns.command.MacroCommand` 47 | :class:`puremvc.patterns.command.SimpleCommand` 48 | """ 49 | 50 | """Multiton error message""" 51 | MULTITON_MSG = "multitonKey for this Notifier not yet initialized!" 52 | 53 | def __init__(self) -> None: 54 | """Initialise the `INotifier` instance with an empty multiton key""" 55 | self.multitonKey: Optional[str] = None 56 | 57 | def send_notification(self, notification_name: str, body: Any = None, type: Optional[str] = None) -> None: 58 | """ 59 | Create and send an `INotification`. 60 | 61 | Keeps us from having to construct new INotification instances in our 62 | implementation code. 63 | 64 | :param notification_name: The name of the notification to be sent. 65 | :type notification_name: str 66 | :param body: The body of the notification (optional). Default is None. 67 | :type body: Any, optional 68 | :param type: The type of the notification (optional). Default is None. 69 | :type type: str, optional 70 | :return: None 71 | """ 72 | if self.facade: self.facade.send_notification(notification_name, body, type) 73 | 74 | def initialize_notifier(self, key: str) -> None: 75 | """ 76 | Initialize this INotifier instance. 77 | 78 | This is how a Notifier gets its multitonKey. Calls to sendNotification 79 | or to access the facade will fail until after this method has been 80 | called. 81 | 82 | Mediators, Commands or Proxies may override this method in order to 83 | send notifications or access the Multiton Facade instance as soon as 84 | possible. They CANNOT access the facade in their constructors, since 85 | this method will not yet have been called. 86 | 87 | :param key: The multitonKey for this INotifier to use 88 | :type key: str 89 | :return: None 90 | """ 91 | self.multitonKey = key 92 | 93 | @property 94 | def facade(self) -> Optional[IFacade]: 95 | """ 96 | Return the Multiton Facade instance 97 | 98 | :return: The instance of IFacade. 99 | :rtype: Optional[IFacade] 100 | """ 101 | if self.multitonKey is None: 102 | raise Exception(self.MULTITON_MSG) 103 | return Facade.get_instance(self.multitonKey, lambda key: Facade(key)) 104 | -------------------------------------------------------------------------------- /src/puremvc/patterns/facade/__init__.py: -------------------------------------------------------------------------------- 1 | from .Facade import Facade 2 | from .Notifier import Notifier 3 | -------------------------------------------------------------------------------- /src/puremvc/patterns/mediator/Mediator.py: -------------------------------------------------------------------------------- 1 | # Mediator.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from typing import Any, List, Optional 8 | 9 | from puremvc.interfaces import IMediator, INotification 10 | from puremvc.patterns.facade import Notifier 11 | 12 | 13 | class Mediator(Notifier, IMediator): 14 | """ 15 | A base `IMediator` implementation. 16 | 17 | See Also 18 | -------- 19 | :class:`puremvc.core.View` 20 | """ 21 | 22 | """NAME (str): The name of the `Mediator`""" 23 | NAME = "Mediator" 24 | 25 | def __init__(self, mediator_name: Optional[str] = None, view_component: Any = None) -> None: 26 | """ 27 | Constructor 28 | 29 | Typically, a `Mediator` will be written to serve 30 | one specific control or group controls and so, 31 | will not have a need to be dynamically named. 32 | 33 | :param mediator_name: A string representing the name of the mediator. If not provided, it defaults to self.NAME. 34 | :type mediator_name: Optional[str] 35 | :param view_component: Any object representing the view component. If not provided, it defaults to None. 36 | :type view_component: Any 37 | """ 38 | super().__init__() 39 | self._mediator_name = self.NAME if mediator_name is None else mediator_name 40 | self._view_component = view_component 41 | 42 | @property 43 | def mediator_name(self) -> str: 44 | """ 45 | Get the name of the `Mediator`. 46 | 47 | :return: The name of the mediator. 48 | :rtype: str 49 | """ 50 | return self._mediator_name 51 | 52 | @property 53 | def view_component(self) -> Any: 54 | """ 55 | Get the `Mediator` view component. 56 | 57 | :return: The view component. 58 | :rtype: Any 59 | """ 60 | return self._view_component 61 | 62 | @view_component.setter 63 | def view_component(self, value: Any) -> None: 64 | """ 65 | Set the `IMediator` view component. 66 | 67 | :param value: The view component 68 | :type value: Any 69 | :return: None 70 | """ 71 | self._view_component = value 72 | 73 | def list_notification_interests(self) -> List[str]: 74 | """ 75 | List the `INotification` names this 76 | `Mediator` is interested in being notified of. 77 | 78 | :return: List the list of `INotification` names 79 | :rtype: List[str] 80 | """ 81 | return [] 82 | 83 | def handle_notification(self, notification: INotification) -> None: 84 | """ 85 | Handle `INotification`. 86 | 87 | Typically, this will be handled in an if/else statement, 88 | with one 'comparison' entry per `INotification` 89 | the `Mediator` is interested in. 90 | 91 | :param notification: The notification to be handled. 92 | :type notification: INotification 93 | :return: None 94 | """ 95 | return 96 | 97 | def on_register(self) -> None: 98 | """ 99 | Called by the View when the Mediator is registered 100 | :return: None 101 | """ 102 | return 103 | 104 | def on_remove(self) -> None: 105 | """ 106 | Called by the View when the Mediator is removed 107 | :return: None 108 | """ 109 | return 110 | -------------------------------------------------------------------------------- /src/puremvc/patterns/mediator/__init__.py: -------------------------------------------------------------------------------- 1 | from .Mediator import Mediator 2 | -------------------------------------------------------------------------------- /src/puremvc/patterns/observer/Notification.py: -------------------------------------------------------------------------------- 1 | # Notification.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from typing import Any, Optional 8 | 9 | from puremvc.interfaces import INotification 10 | 11 | 12 | class Notification(INotification): 13 | """ 14 | A base `INotification` implementation. 15 | 16 | PureMVC does not rely upon underlying event models such 17 | as the one provided with Flash, and ActionScript 3 does 18 | not have an inherent event model. 19 | 20 | The Observer Pattern as implemented within PureMVC exists 21 | to support event-driven communication between the 22 | application and the actors of the MVC triad. 23 | 24 | Notifications are not meant to be a replacement for Events 25 | in Flex/Flash/Apollo. Generally, `IMediator` implementors 26 | place event listeners on their view components, which they 27 | then handle in the usual way. This may lead to the broadcast of `Notification` to 28 | trigger `ICommand` or to communicate with other `IMediators`. `IProxy` and `ICommand` 29 | instances communicate with each other and `IMediator`s 30 | by broadcasting `INotification`. 31 | 32 | A key difference between Flash `Event` and PureMVC 33 | `Notification` is that `Event` follows the 34 | 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 35 | until some parent component handles the `Event`, while 36 | PureMVC `Notification` follows a 'Publish/Subscribe' 37 | pattern. PureMVC classes need not be related to each other in a 38 | parent/child relationship to communicate with one another 39 | using `Notification`. 40 | 41 | See Also 42 | -------- 43 | :class:`puremvc.patterns.observer.Observer` 44 | """ 45 | 46 | def __init__(self, name: str, body: Any = None, type: Optional[str] = None) -> None: 47 | """ 48 | Constructor. 49 | 50 | :param name: name of the `Notification` instance. (required) 51 | :type name: str 52 | :param body: the `Notification` body. (optional) 53 | :type body: Any 54 | :param type: The type of the note. Defaults to None. 55 | :type type: str 56 | """ 57 | self._name = name 58 | self._body = body 59 | self._type = type 60 | 61 | @property 62 | def name(self) -> str: 63 | """ 64 | Get the name of the `Notification` instance. 65 | 66 | :return: The name of the `Notification` instance. 67 | :rtype: str 68 | """ 69 | return self._name 70 | 71 | @property 72 | def body(self) -> Any: 73 | """ 74 | This method returns the value of the `_body` attribute. 75 | 76 | :return: The value of the `_body` attribute. 77 | :rtype: Any 78 | """ 79 | return self._body 80 | 81 | @body.setter 82 | def body(self, body: Any) -> None: 83 | """ 84 | Set the body of the `Notification` instance. 85 | 86 | :param body: The new value for the body. 87 | :type body: Any 88 | :return: None 89 | """ 90 | self._body = body 91 | 92 | @property 93 | def type(self) -> Optional[str]: 94 | """ 95 | Get the body of the `Notification` instance. 96 | 97 | :return: The type of the object. 98 | :rtype: Optional[str] 99 | """ 100 | return self._type 101 | 102 | @type.setter 103 | def type(self, note_type: str) -> None: 104 | """ 105 | Set the type of the `Notification` instance. 106 | :param note_type: The new type for the `Notification` instance. 107 | :type note_type: str 108 | :return: None 109 | """ 110 | self._type = note_type 111 | 112 | def __repr__(self) -> str: 113 | """ 114 | Get the string representation of the `Notification` instance. 115 | 116 | :return: The string representation of the `Notification` instance. 117 | :rtype: str 118 | """ 119 | return ("Notification Name: " + self.name + 120 | "\nBody:" + "None" if self.body is None else repr(self.body) + 121 | "\nType:" + ("None" if self.type is None else repr(self.type))) 122 | -------------------------------------------------------------------------------- /src/puremvc/patterns/observer/Observer.py: -------------------------------------------------------------------------------- 1 | # Observer.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from typing import Any, Callable, Optional 8 | 9 | from puremvc.interfaces import IObserver, INotification 10 | 11 | 12 | class Observer(IObserver): 13 | """ 14 | A base `IObserver` implementation. 15 | 16 | An `Observer` is an object that encapsulates information 17 | about an interested object with a method that should 18 | be called when a particular `INotification` is broadcast. 19 | 20 | In PureMVC, the `Observer` class assumes these responsibilities: 21 | 22 | Encapsulate the notification (callback) method of the interested object. 23 | 24 | Encapsulate the notification context (this) of the interested object. 25 | 26 | Provide methods for setting the notification method and context. 27 | 28 | Provide a method for notifying the interested object. 29 | 30 | See Also 31 | -------- 32 | :class:`puremvc.core.View` 33 | :class:`puremvc.patterns.observer.Notification` 34 | """ 35 | 36 | def __init__(self, notify_method: Optional[Callable[[INotification], None]] = None, notify_context: object = None) -> None: 37 | """ 38 | Constructor. 39 | 40 | The notification method on the interested object should take 41 | one parameter of type `INotification` 42 | 43 | :param notify_method: The notification method of the interested object 44 | :type notify_method: Optional[Callable[[INotification], None]] 45 | :param notify_context: the notification context of the interested object 46 | :type notify_context: object 47 | """ 48 | self._notify_method: Optional[Callable[[INotification], None]] = notify_method 49 | self._notify_context: object = notify_context 50 | 51 | @property 52 | def notify_method(self) -> Optional[Callable[[INotification], None]]: 53 | """ 54 | Get the notification method. 55 | 56 | :return: The notify method. 57 | :rtype: Optional[Callable[[INotification], None] 58 | """ 59 | return self._notify_method 60 | 61 | @notify_method.setter 62 | def notify_method(self, value: Callable[[INotification], None]) -> None: 63 | """ 64 | Set the notification context. 65 | 66 | :param value: A callable function that takes an INotification object as its parameter. 67 | :type value: Callable[[INotification], None] 68 | :return: None 69 | """ 70 | self._notify_method = value 71 | 72 | @property 73 | def notify_context(self) -> object: 74 | """ 75 | Get the notification context. 76 | 77 | :return: The notify context. 78 | :rtype: object 79 | """ 80 | return self._notify_context 81 | 82 | @notify_context.setter 83 | def notify_context(self, value: object) -> None: 84 | """ 85 | Set the notification context. 86 | 87 | :param value: The notification context (self) of the interested object. 88 | :type value: object 89 | :return: None 90 | """ 91 | self._notify_context = value 92 | 93 | def notify_observer(self, notification: INotification) -> None: 94 | """ 95 | Notify the interested object. 96 | 97 | :param notification: The `INotification` to pass to the interested 98 | :type notification: INotification 99 | :return: None 100 | """ 101 | if self._notify_method is not None: 102 | self._notify_method(notification) 103 | 104 | def compare_notify_context(self, obj: object) -> bool: 105 | """ 106 | Compare an object to the notification context. 107 | 108 | :param obj: The object to compare with the notify context. 109 | :type obj: object 110 | :return: True if the given object is equal to the notify context, False otherwise. 111 | :rtype: bool 112 | """ 113 | return obj == self._notify_context 114 | -------------------------------------------------------------------------------- /src/puremvc/patterns/observer/__init__.py: -------------------------------------------------------------------------------- 1 | from .Notification import Notification 2 | from .Observer import Observer 3 | -------------------------------------------------------------------------------- /src/puremvc/patterns/proxy/Proxy.py: -------------------------------------------------------------------------------- 1 | # Proxy.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | from typing import Any, Optional 8 | 9 | from puremvc.interfaces import IProxy 10 | from puremvc.patterns.facade import Notifier 11 | 12 | 13 | class Proxy(IProxy, Notifier): 14 | """ 15 | A base `IProxy` implementation. 16 | 17 | In PureMVC, `Proxy` classes are used to manage parts of the 18 | application's data model. 19 | 20 | A `Proxy` might simply manage a reference to a local data object, 21 | in which case interacting with it might involve setting and 22 | getting of its data in synchronous fashion. 23 | 24 | `Proxy` classes are also used to encapsulate the application's 25 | interaction with remote services to save or retrieve data, in which case, 26 | we adopt an asynchronous idiom; setting data (or calling a method) on the 27 | `Proxy` and listening for a `Notification` to be sent 28 | when the `Proxy` has retrieved the data from the service. 29 | 30 | See Also 31 | -------- 32 | :class:`puremvc.core.Model` 33 | """ 34 | 35 | """NAME (str): The name of the `Proxy`""" 36 | NAME = "Proxy" 37 | 38 | def __init__(self, proxy_name: Optional[str] = None, data: Any = None) -> None: 39 | """ 40 | Constructor 41 | 42 | :param proxy_name: The name of the proxy. Defaults to None. 43 | :type proxy_name: Optional[str] 44 | :param data: The data associated with the object. Defaults to None. 45 | :type data: Any 46 | """ 47 | super().__init__() 48 | self._proxy_name = self.NAME if proxy_name is None else proxy_name 49 | self.data = data 50 | 51 | @property 52 | def proxy_name(self) -> str: 53 | """ 54 | Get the `Proxy` name 55 | 56 | :return: The proxy name. 57 | :rtype: str 58 | """ 59 | return self._proxy_name 60 | 61 | @property 62 | def data(self) -> Any: 63 | """ 64 | Get the `Proxy` data 65 | 66 | :return: The Proxy `data` object. 67 | :rtype: Any 68 | """ 69 | return self._data 70 | 71 | @data.setter 72 | def data(self, value: Any) -> None: 73 | """ 74 | Set the `Proxy` data 75 | 76 | :param value: The Proxy data object 77 | :type value: Any 78 | :return: None 79 | """ 80 | self._data = value 81 | 82 | def on_register(self) -> None: 83 | """ 84 | Called by the `Model` when the `Proxy` is registered 85 | :return: None 86 | """ 87 | return 88 | 89 | def on_remove(self) -> None: 90 | """ 91 | Called by the `Model` when the `Proxy` is removed 92 | :return: None 93 | """ 94 | return 95 | -------------------------------------------------------------------------------- /src/puremvc/patterns/proxy/__init__.py: -------------------------------------------------------------------------------- 1 | from .Proxy import Proxy 2 | -------------------------------------------------------------------------------- /test/core/Model_test.py: -------------------------------------------------------------------------------- 1 | # Model_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | from typing import List 9 | 10 | from puremvc.core import Model 11 | from puremvc.interfaces import IModel 12 | from puremvc.patterns.proxy import Proxy 13 | 14 | 15 | class ModelTest(unittest.TestCase): 16 | """Test the PureMVC Model class.""" 17 | 18 | def test_get_instance(self): 19 | """Tests the Model Multiton Factory Method""" 20 | # Test Factory Method 21 | model = Model.get_instance("ModelTestKey1", lambda k: Model(k)) 22 | 23 | # test assertions 24 | self.assertIsNotNone(model, "Expecting instance not None") 25 | self.assertIsInstance(model, IModel, "Expecting instance implements IModel") 26 | self.assertEqual(model, Model.get_instance("ModelTestKey1", lambda k: Model(k))) 27 | self.assertNotEqual(model, Model.get_instance("Key123", lambda k: Model(k))) 28 | 29 | def test_register_and_retrieve_proxy(self): 30 | """ 31 | Tests the proxy registration and retrieval methods. 32 | Tests `register_proxy` and `retrieve_proxy` in the same test. 33 | These methods cannot currently be tested separately 34 | in any meaningful way other than to show that the 35 | methods do not throw exception when called. 36 | 37 | :return: 38 | """ 39 | # register a proxy and retrieve it. 40 | model = Model.get_instance("ModelTestKey2", lambda k: Model(k)) 41 | model.register_proxy(Proxy("colors", ["red", "green", "blue"])) 42 | proxy = model.retrieve_proxy("colors") 43 | data: List[str] = proxy.data 44 | 45 | # test assertions 46 | self.assertIsNotNone(data, "Expecting data not None") 47 | self.assertTrue(isinstance(data, List), "") 48 | self.assertTrue(len(data) == 3, "Expecting len(data) == 3") 49 | self.assertTrue(data[0] == "red", "Expecting data[0] == 'red'") 50 | self.assertTrue(data[1] == "green", "Expecting data[1] == 'green'") 51 | self.assertTrue(data[2] == "blue", "Expecting data[2] == 'blue'") 52 | 53 | def test_register_and_remove_proxy(self): 54 | """Tests the proxy removal method.""" 55 | # register a proxy, remove it, then try to retrieve it 56 | model = Model.get_instance("ModelTestKey3", lambda k: Model(k)) 57 | proxy = Proxy("sizes", ["7", "13", "21"]) 58 | model.register_proxy(proxy) 59 | 60 | # remove the proxy 61 | removed_proxy = model.remove_proxy("sizes") 62 | 63 | # assert that we removed the appropriate proxy 64 | self.assertTrue(removed_proxy.proxy_name == "sizes", "Expecting removed_proxy.proxy_name == 'sizes'") 65 | 66 | # ensure that the proxy is no longer retrievable from the model 67 | proxy = model.retrieve_proxy("colors") 68 | 69 | # test assertions 70 | self.assertIsNone(proxy, "Expecting proxy is None") 71 | 72 | def test_has_proxy(self): 73 | """Tests the hasProxy Method""" 74 | # register a proxy 75 | model = Model.get_instance("ModelTestKey4", lambda k: Model(k)) 76 | proxy = Proxy("aces", ["clubs", "spades", "hearts", "diamonds"]) 77 | model.register_proxy(proxy) 78 | 79 | # assert that the model.hasProxy method returns true 80 | # for that proxy name 81 | self.assertTrue(model.has_proxy("aces"), "Expecting model.has_proxy('aces') == true") 82 | 83 | # remove the proxy 84 | model.remove_proxy("aces") 85 | 86 | # assert that the model.hasProxy method returns false 87 | # for that proxy name 88 | self.assertFalse(model.has_proxy("aces"), "Expecting model.has_proxy('aces') == false") 89 | 90 | def test_on_register_and_on_Remove(self): 91 | """Tests that the Model calls the on_register and on_remove methods""" 92 | # Get a Multiton View instance 93 | model = Model.get_instance("ModelTestKey5", lambda k: Model(k)) 94 | 95 | # Create and register the test mediator 96 | proxy = ModelTestProxy() 97 | model.register_proxy(proxy) 98 | 99 | # assert that on_register was called, and the proxy responded by setting its data accordingly 100 | self.assertTrue(proxy.data == ModelTestProxy.ON_REGISTER_CALLED, 101 | "Expecting proxy.data == ModelTestProxy.ON_REGISTER_CALLED") 102 | 103 | # Remove the component 104 | model.remove_proxy(ModelTestProxy.NAME) 105 | 106 | # assert that onRemove was called, and the proxy responded by setting its data accordingly 107 | self.assertTrue(proxy.data == ModelTestProxy.ON_REMOVE_CALLED, 108 | "Expecting proxy.data == ModelTestProxy.ON_REMOVE_CALLED") 109 | 110 | 111 | class ModelTestProxy(Proxy): 112 | NAME = "ModelTestProxy" 113 | ON_REGISTER_CALLED = "onRegister Called" 114 | ON_REMOVE_CALLED = "onRemove Called" 115 | 116 | def __init__(self): 117 | super().__init__(ModelTestProxy.NAME) 118 | 119 | def on_register(self): 120 | self.data = ModelTestProxy.ON_REGISTER_CALLED 121 | 122 | def on_remove(self): 123 | self.data = ModelTestProxy.ON_REMOVE_CALLED 124 | 125 | 126 | if __name__ == '__main__': 127 | unittest.main() 128 | -------------------------------------------------------------------------------- /test/patterns/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/patterns/command/MacroCommand_test.py: -------------------------------------------------------------------------------- 1 | # MacroCommand_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.interfaces import INotification 10 | from puremvc.patterns.command import SimpleCommand, MacroCommand 11 | from puremvc.patterns.observer import Notification 12 | 13 | 14 | class MacroCommandTest(unittest.TestCase): 15 | """ 16 | Tests operation of a 'MacroCommand'. 17 | 18 | This test creates a new 'Notification', adding a 19 | 'MacroCommandTestVO' as the body. 20 | It then creates a 'MacroCommandTestCommand' and invokes 21 | its 'execute' method, passing in the 22 | 'Notification'. 23 | 24 | The 'MacroCommandTestCommand' has defined an 25 | 'initializeMacroCommand' method, which is 26 | called automatically by its constructor. In this method, 27 | the 'MacroCommandTestCommand' adds 2 SubCommands 28 | to itself, 'MacroCommandTestSub1Command' and 29 | 'MacroCommandTestSub2Command'. 30 | 31 | The 'MacroCommandTestVO' has 2 result properties, 32 | one is set by 'MacroCommandTestSub1Command' by 33 | multiplying the input property by 2, and the other is set 34 | by 'MacroCommandTestSub2Command' by multiplying 35 | the input property by itself. 36 | 37 | Success is determined by evaluating the 2 result properties 38 | on the 'MacroCommandTestVO' that was passed to 39 | the 'MacroCommandTestCommand' on the Notification 40 | body. 41 | """ 42 | 43 | def test_macro_command_execute(self): 44 | # Create the VO 45 | vo = MacroCommandTestVO(5) 46 | 47 | # Create the Notification (note) 48 | note = Notification("MacroCommandTest", vo) 49 | 50 | # Create the SimpleCommand 51 | command = MacroCommandTestCommand() 52 | command.initialize_notifier("MacroCommandTestKey1") 53 | 54 | # Execute the SimpleCommand 55 | command.execute(note) 56 | 57 | # test assertions 58 | self.assertTrue(vo.result1 == 10) 59 | self.assertTrue(vo.result2 == 25) 60 | 61 | 62 | class MacroCommandTestCommand(MacroCommand): 63 | 64 | def initialize_macro_command(self): 65 | """Initialize the MacroCommandTestCommand by adding its 2 SubCommands.""" 66 | self.add_subcommand(lambda: MacroCommandTestSub1Command()) 67 | self.add_subcommand(lambda: MacroCommandTestSub2Command()) 68 | 69 | 70 | class MacroCommandTestSub1Command(SimpleCommand): 71 | def execute(self, notification: INotification): 72 | """ 73 | Fabricate a result by multiplying the input by 2 74 | 75 | :param notification: Notification carrying the 'MacroCommandTestVO' 76 | :type notification: INotification 77 | """ 78 | vo = notification.body 79 | 80 | # Fabricate a result 81 | vo.result1 = 2 * vo.input 82 | 83 | 84 | class MacroCommandTestSub2Command(SimpleCommand): 85 | """A SimpleCommand subclass used by MacroCommandTestCommand.""" 86 | 87 | def execute(self, notification: INotification): 88 | """ 89 | Fabricate a result by multiplying the input by itself 90 | :param notification: event the 'IEvent' carrying the 'MacroCommandTestVO' 91 | :type notification: INotification 92 | """ 93 | vo = notification.body 94 | 95 | # Fabricate a result 96 | vo.result2 = vo.input * vo.input 97 | 98 | 99 | class MacroCommandTestVO: 100 | def __init__(self, data: int): 101 | """ 102 | Constructor. 103 | 104 | :param data: The number to be fed to the MacroCommandTestCommand 105 | """ 106 | self.input = data 107 | self.result1 = 0 108 | self.result2 = 0 109 | 110 | 111 | if __name__ == '__main__': 112 | unittest.main() 113 | -------------------------------------------------------------------------------- /test/patterns/command/SimpleCommand_test.py: -------------------------------------------------------------------------------- 1 | # SimpleCommand_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.interfaces import INotification 10 | from puremvc.patterns.command import SimpleCommand 11 | from puremvc.patterns.observer import Notification 12 | 13 | 14 | class SimpleCommandTest(unittest.TestCase): 15 | """Test the PureMVC SimpleCommand class.""" 16 | 17 | def test_simple_command_execute(self): 18 | """ 19 | Tests the `execute` method of a `SimpleCommand`. 20 | 21 | This test creates a new `Notification`, adding a 22 | `SimpleCommandTestVO` as the body. 23 | It then creates a `SimpleCommandTestCommand` and invokes 24 | its `execute` method, passing in the note. 25 | 26 | Success is determined by evaluating a property on the 27 | object that was passed on the Notification body, which will 28 | be modified by the SimpleCommand 29 | """ 30 | # Create the VO 31 | vo = SimpleCommandTestVO(5) 32 | 33 | # Create the Notification (note) 34 | note = Notification("SimpleCommandTestNote", vo) 35 | 36 | # Create the SimpleCommand 37 | command = SimpleCommandTestCommand() 38 | 39 | # Execute the SimpleCommand 40 | command.execute(note) 41 | 42 | # test assertions 43 | self.assertTrue(vo.result == 10, "Expecting vo.result == 10") 44 | 45 | 46 | class SimpleCommandTestCommand(SimpleCommand): 47 | """A SimpleCommand subclass used by SimpleCommandTest.""" 48 | 49 | def execute(self, notification: INotification): 50 | """ 51 | Fabricate a result by multiplying the input by 2 52 | :param notification: The `INotification` carrying the `SimpleCommandTestVO` 53 | """ 54 | vo = notification.body 55 | 56 | # Fabricate a result 57 | vo.result = 2 * vo.input 58 | 59 | 60 | class SimpleCommandTestVO: 61 | 62 | def __init__(self, data: int): 63 | """ 64 | Constructor. 65 | 66 | :param data: The number to be fed to the SimpleCommandTestCommand 67 | """ 68 | self.input = data 69 | self.result = 0 70 | 71 | 72 | if __name__ == '__main__': 73 | unittest.main() 74 | -------------------------------------------------------------------------------- /test/patterns/mediator/Mediator_test.py: -------------------------------------------------------------------------------- 1 | # Mediator_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.patterns.mediator import Mediator 10 | 11 | 12 | class MediatorTest(unittest.TestCase): 13 | """Test the PureMVC Mediator class.""" 14 | 15 | def test_name_accessor(self): 16 | """Tests getting the name using Mediator class accessor method. """ 17 | # Create a new Mediator and use accessors to set the mediator name 18 | mediator = Mediator() 19 | 20 | # test assertions 21 | self.assertEqual(True, mediator.mediator_name == "Mediator", 22 | "Expecting mediator.mediator_name == Mediator.NAME") 23 | 24 | def test_view_accessor(self): 25 | """Tests getting the name using Mediator class accessor method. """ 26 | # Create a view object 27 | view = object() 28 | 29 | # Create a new Proxy and use accessors to set the proxy name 30 | mediator = Mediator(Mediator.NAME, view) 31 | 32 | # test assertions 33 | self.assertIsNotNone(mediator.view_component, "Expecting mediator.view_component not None") 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/patterns/observer/Notification_test.py: -------------------------------------------------------------------------------- 1 | # Notification_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.patterns.observer import Notification 10 | 11 | 12 | class NotificationTest(unittest.TestCase): 13 | """Test the PureMVC Notification class.""" 14 | 15 | def test_name_accessor(self): 16 | """Tests setting and getting the name using Notification class accessor methods.""" 17 | # Create a new Notification and use accessors to set the note name 18 | note = Notification("TestNote") 19 | 20 | # test assertions 21 | self.assertTrue(note.name == "TestNote", "Expecting note.name == 'TestNote'") 22 | 23 | def test_test_body_accessors(self): 24 | """Tests setting and getting the body using Notification class accessor methods.""" 25 | # Create a new Notification and use accessors to set the body 26 | note = Notification("TestNote") 27 | note.body = 5 28 | 29 | # test assertions 30 | self.assertTrue(note.body == 5, "Expecting note.body == 5") 31 | 32 | def test_constructor(self): 33 | """Tests setting the name and body using the Notification class Constructor.""" 34 | # Create a new Notification using the Constructor to set the note name and body 35 | note = Notification("TestNote", 5, "TestNoteType") 36 | 37 | # test assertions 38 | self.assertTrue(note.name == "TestNote", "Expecting note.name == 'TestNote'") 39 | self.assertTrue(note.body == 5, "Expecting note.body == 5") 40 | self.assertTrue(note.type == "TestNoteType", "Expecting note.type == 'TestNoteType'") 41 | 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /test/patterns/observer/Notifier_test.py: -------------------------------------------------------------------------------- 1 | # Notifier_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.interfaces import INotification 10 | from puremvc.patterns.command import SimpleCommand 11 | from puremvc.patterns.facade import Notifier 12 | 13 | 14 | class NotifierTest(unittest.TestCase): 15 | """Test the PureMVC Notifier class.""" 16 | 17 | def test_register_command_and_send_notification(self): 18 | # Create the Notifier 19 | notifier = Notifier() 20 | 21 | # Create the Facade, register the NotifierTestCommand to 22 | # handle 'NotifierTest' notifications 23 | notifier.initialize_notifier("NotifierTestKey1") 24 | notifier.facade.register_command("NotifierTestNote", lambda: NotifierTestCommand()) 25 | 26 | # Send notification. The Command associated with the event 27 | # (NotifierTestCommand) will be invoked, and will multiply 28 | # the vo.input value by 2 and set the result on vo.result 29 | vo = NotifierTestVO(32) 30 | notifier.send_notification("NotifierTestNote", vo) 31 | 32 | # test assertions 33 | self.assertTrue(vo.result == 64, "Expecting vo.result == 64") 34 | 35 | 36 | class NotifierTestCommand(SimpleCommand): 37 | def execute(self, notification: INotification): 38 | """ 39 | Fabricate a result by multiplying the input by 2 40 | :param notification: the Notification carrying the FacadeTestVO 41 | :type notification: INotification 42 | """ 43 | vo = notification.body 44 | 45 | # Fabricate a result 46 | vo.result = 2 * vo.input 47 | 48 | 49 | class NotifierTestVO: 50 | def __init__(self, data: int): 51 | """ 52 | Constructor. 53 | :param data: input the number to be fed to the FacadeTestCommand 54 | :type data: int 55 | """ 56 | self.input = data 57 | self.result = None 58 | 59 | 60 | if __name__ == '__main__': 61 | unittest.main() 62 | -------------------------------------------------------------------------------- /test/patterns/observer/Observer_test.py: -------------------------------------------------------------------------------- 1 | # Observer_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.interfaces import INotification 10 | from puremvc.patterns.observer import Notification 11 | from puremvc.patterns.observer import Observer 12 | 13 | 14 | class ObserverTest(unittest.TestCase): 15 | """ 16 | Tests PureMVC Observer class. 17 | 18 | Since the Observer encapsulates the interested object's 19 | callback information, there are no getters, only setters. 20 | It is, in effect, write-only memory. 21 | 22 | Therefore, the only way to test it is to set the 23 | notification method and context and call the notifyObserver 24 | method. 25 | """ 26 | 27 | def test_observer_accessors(self): 28 | """Tests observer class when initialized by accessor methods.""" 29 | # Create observer with None args, then 30 | # use accessors to set notification method and context 31 | observer = Observer(None, None) 32 | self.observer_test_var = 0 33 | 34 | observer.notify_context = self 35 | observer.notify_method = self.observer_test_method 36 | 37 | # create a test event, setting a payload value and notify 38 | # the observer with it. since the observer is this class 39 | # and the notification method is observer_test_method, 40 | # successful notification will result in our local 41 | # observer_test_var being set to the value we pass in 42 | # on the note body. 43 | note = Notification("ObserverTestNote", 10) 44 | observer.notify_observer(note) 45 | 46 | # test assertions 47 | self.assertTrue(self.observer_test_var == 10, "Expecting observer_test_var = 10") 48 | 49 | def test_observer_constructor(self): 50 | """Tests observer class when initialized by constructor.""" 51 | # Create observer passing in notification method and context 52 | observer = Observer(self.observer_test_method, self) 53 | 54 | # create a test note, setting a body value and notify 55 | # the observer with it. since the observer is this class 56 | # and the notification method is observer_test_method, 57 | # successful notification will result in our local 58 | # observer_test_var being set to the value we pass in 59 | # on the note body. 60 | note = Notification("ObserverTestNote", 5) 61 | observer.notify_observer(note) 62 | self.assertTrue(self.observer_test_var == 5, "Expecting observerTestVar = 5") 63 | 64 | def test_compare_notify_context(self): 65 | """Tests the compareNotifyContext method of the Observer class""" 66 | # Create observer passing in notification method and context 67 | observer = Observer(self.observer_test_method, self) 68 | neg = object() 69 | 70 | # test assertions 71 | self.assertFalse(observer.compare_notify_context(neg), "observer.compare_notify_context(neg) == False") 72 | self.assertTrue(observer.compare_notify_context(self), "observer.compare_notify_context(self) == True") 73 | 74 | def observer_test_method(self, notification: INotification): 75 | """A function that is used as the observer notification 76 | method. It multiplies the input number by the 77 | observer_test_var value""" 78 | # A test variable that proves the notify method was 79 | # executed with 'self' as its execution context 80 | self.observer_test_var = notification.body 81 | 82 | 83 | if __name__ == "__main__": 84 | unittest.main() 85 | -------------------------------------------------------------------------------- /test/patterns/proxy/Proxy_test.py: -------------------------------------------------------------------------------- 1 | # Proxy_test.py 2 | # PureMVC Python Multicore 3 | 4 | # Copyright(c) 2025 Saad Shams 5 | # Your reuse is governed by the BSD 3-Clause License 6 | 7 | import unittest 8 | 9 | from puremvc.patterns.proxy import Proxy 10 | 11 | 12 | class ProxyTest(unittest.TestCase): 13 | """Test the PureMVC Proxy class.""" 14 | 15 | def test_name_accessor(self): 16 | """Tests getting the name using Proxy class accessor method. Setting can only be done in constructor.""" 17 | # Create a new Proxy and use accessors to set the proxy name 18 | proxy = Proxy("TestProxy") 19 | 20 | # test assertions 21 | self.assertEqual(True, proxy.proxy_name == "TestProxy", "Expecting proxy.proxy_name == 'TestProxy'") 22 | 23 | def test_data_accessor(self): 24 | """Tests setting and getting the data using Proxy class accessor methods.""" 25 | # Create a new Proxy and use accessors to set the data 26 | proxy = Proxy("colors") 27 | proxy.data = ["red", "green", "blue"] 28 | data = proxy.data 29 | 30 | # test assertions 31 | self.assertEqual(True, len(data) == 3, "Expecting len(data) == 3") 32 | self.assertEqual(True, data[0] == "red", "Expecting data[0] == 'red'") 33 | self.assertEqual(True, data[1] == "green", "Expecting data[1] == 'green'") 34 | self.assertEqual(True, data[2] == "blue", "Expecting data[2] == 'blue'") 35 | 36 | def test_constructor(self): 37 | """Tests setting the name and body using the Notification class Constructor.""" 38 | # Create a new Proxy using the Constructor to set the name and data 39 | proxy = Proxy("colors", ["red", "green", "blue"]) 40 | data = proxy.data 41 | 42 | # test assertions 43 | self.assertIsNotNone(proxy, "Expecting proxy not None") 44 | self.assertEqual(True, len(data) == 3, "Expecting len(data) == 3") 45 | self.assertEqual(True, data[0] == "red", "Expecting data[0] == 'red'") 46 | self.assertEqual(True, data[1] == "green", "Expecting data[1] == 'green'") 47 | self.assertEqual(True, data[2] == "blue", "Expecting data[2] == 'blue'") 48 | 49 | 50 | if __name__ == '__main__': 51 | unittest.main() 52 | --------------------------------------------------------------------------------