This project creates a single scripting and markup rendering language that is able to build:
- server/client apps w/ crud db operations
- interactive user interfaces
It is designed to be lightweight, cross-os and cross-language w/ interpreters and renderers in python and js currently, eventually also supporting c, go and haskell. JS and YAML have been chosen as the serialization format. Unlike the modern browser where your state is spread between 3 languages (html/js/css) a single JS or YAML file defines everything. Layout, style, scripting, even the data model for CRUD operations. A simple syntax is able to define models with fields and their types and then a framework app creates server endpoints, cli commands and db operations for the models. There is another syntax for rendering visual elements such as buttons, text and inputs and their layouts. Both share an extension set of functions for scripting.
To accomplish this there and three script specs:
- scripting - for running a result and returning a machine readable response (cli)
- pages - for rendering an interactive page
- application - for defining a crud application w/ server, cli, gui, and db
See here for full language function documentation.
This scripting spec enables executing a script and returning an output in a machine readable format. Ideally suited for cli and automation.
spec name: script-beta-1
sample files: src/mspec/data/lingo/scripts
bootstrap example file: python -m mspec example basic_math.json
execute w python cli: python -m mspec execute basic_math.json
clients
This scripting spec allows rendering an interactive page including layout, style, scripting and state.
spec name: page-beta-1
sample files: src/mspec/data/lingo/pages
bootstrap example file: python -m mspec example hello-world-page.yaml
execute and dump json buffer: python -m mspec run hello-world-page.yaml
open in pybrowser2: python -m mspec.browser2 --spec hello-world-page.yaml
clients
spec name: generator-beta-1
A spec for defining an application. Define data models with fields and their types and drive a framework with db crud ops and http api server, cli and gui interfaces wrapping them. Define an operation with input param types and return types and get a server, cli and gui interface to wrap it.
sample files: src/mspec/data/generator
bootstrap example file: python -m mspec example my-sample-store.yaml
clients
The python cli can output built in example files, execute scripts and return the output or render and print the document buffer of a page spec.
# Print names of all built in specs:
python -m mspec specs
# Copy builtin spec to cwd:
python -m mspec example basic_math.json
# Execute script and print output:
python -m mspec execute basic_math.json
{
"type": "float",
"value": 20.0
}
# Render a page spec's document buffer and print to screen:
python -m mspec run hello-world-page.yaml
[
{
"heading": "Hello, World",
"level": 1
},
{
"text": "I am a sample page!"
}
]Covers:
- mspec cli
- execute script spec
- render buffer for page spec
Run commands from root of repo:
python -m unittestpython -m unittest tests.test_lingo
python -m unittest tests.test_mspec
python -m unittest tests.test_mtesterA browser2 implementation in Python using the built in tkinter library.
python -m mspec.browser2
You can open any spec json file with this:
python -m mspec.browser2 --spec functions.json
functions.json is a built in example spec and the above command will work even if that file is not in your working directory. the --spec arg will first be check to see if the path exists, if not then the arg will be checked against built in specs.
The javascript (legacy browser) browser2 implementation is available in browser2/js.
setup
cd browser2/js
npm install
run dev server
./server.py
Check output for localhost address (ex: http://localhost:8000)
With dev server running, in another terminal run:
npm run test
The mapp framework is used to run an application defined in the application spec. Its features include:
- db crud/list ops for data models
- procedured defined in scripting language
- server with:
- crud/list endpoints for all data models
- validates incoming data
- POST endoints for all ops
- validates incoming user params
- validates output response before sending
- crud/list endpoints for all data models
- http client that calls the server
- functions for each endpoint (models and ops)
- cli for everything
- run crud/list using local db or remote server
- run ops locally or via remote server
- authentication and users
The mapp python framework code is in src/mapp. It uses the mapp spec to define an app.
The example implementation of a mapp app is in templates/mapp-py, use this for testing the framework.
The UI for a mapp app is defined by lingo page files in src/mspec/data/lingo/pages, specifically the files in this dir starting with builtin-mapp.
The mapp application serves these wrapped in html for the browser. mapp does this when creating static file routes in src/mapp/server.py. These files are also dependent on the lingo script JS interpreter which is in browser2/js.
To test develop and test the JS lingo interpreter use the dev lingo server browser2/js/server.py and navigate to it in your browser.
Use ./build.sh to sync the files in browser2/js to the python mapp app in src/mspec/data/mapp-ui/src. These are the lingo interpreter files that the template app templates/mapp-py will use for it's UI. For development testing you can run the mapp-py server like this to force it to use the development js interpreter without needing to use build.sh to sync your chages.
./server.sh --ui-src ../../browser2/js/src/
Eventually this spec will be able to generate an app including python, html, shell scripts, etc. The template is still being finished so that's not available yet. For now the test app can be run against the test spec as follows.
Change to mapp directory:
cd templates/mapp-py
run server:
./server.sh --ui-src ../../browser2/js/src/
With server running:
- tail logs -
tail -f ./app/server.log - cli -
./run.sh -h - view ui in browser - http://localhost:3003 (confirm port in server out/logs)
Tests will run their own servers, with own sqlite file, on different ports that don't overlap with default port used by ./server.sh.
From dir: cd templates/mapp-py
- python
- run tests -
./test.sh - test logs and data in dir:
./mapp-tests
- run tests -
- browser
- start server -
./test.sh --servers-only - in another terminal run test
- headless:
npm run test - interactively:
npm run test-ui
- headless:
- start server -
See here for code style guidelines.
This environment will be used to develop the template apps, mspec and mtemplate modules and browser2 python implementation.
git clone https://github.com/medium-tech/mspec.git
cd mspec
python3 -m venv .venv --upgrade-deps
source .venv/bin/activate
pip install -e .
python
./src/mapp/- mapp framework for server application spec./src/mspec/- language parsing, executing, buffering./src/mspec/pybrowser2- browser2 implementation (page spec gui)./src/mtemplate/- templating (see here)./src/mtester/- testing (see here)
javascript
browser2/js- browser2 implementation (page spec gui) & dev server
templates template apps from which templates are extracted.
./templates/mapp-py- implementation of mapp framework./templates/*- Currentlymapp-pyis in use with the mapp framework, and the others are deprecated. (see here for more info)
pip install -r requirements-dev.txt
-
run
python -m mtemplate cacheto ensure distributed templates are up to date -
increment version in
pyproject.tomlfile -
run tests
- mspec cli
- mapp cli tests
- mapp browser tests
- browser2 js dev tests
-
build distributions
python3 -m build --sdist python3 -m build --wheel -
check distributions for errors
./build_test.py twine check dist/* -
upload to pypi (will prompt for api key, no other config needed)
twine upload dist/*
- lightweight
- pythonic
- it just works, quickly
All specs are written in either json or yaml. The structure is the same regardless of the serialization format. Yaml was chosen because it's simple syntax is both human readable and machine parsable. JSON was chosen because because of it's wide availability, many languages have a built in parser. Both of them generally serialize the same data and have simple serialization/deserialization apis so implementing both is trivial.
Testing framework to automate gui testing across languages
A templating project to embed templating commands into real code.
Templates in ./templates:
mapp-py- incomplete - for the mapp framework once the framework stabilizes.go- deprecatedpy- deprecatedbrowser1- deprecated
see docs: