├── .gitignore
├── LICENSE
├── README-V0.md
├── README.md
├── setup.py
├── update-static.sh
└── vuejspython
├── __init__.py
├── builtin
├── create-demo-files.vue
├── diff.min.js
├── edit-file.vue
├── rotate-files.vue
├── serve-videos.vue
├── toggle-exam.vue
└── view-file.vue
├── fsapi.js
├── index.html
└── run.py
/.gitignore:
--------------------------------------------------------------------------------
1 | unzip-*/
2 | epoch*/
3 | build/
4 | dist/
5 | __pycache__/
6 | *.egg-info/
7 | demo/
8 | .params.json
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Rémi EMONET
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README-V0.md:
--------------------------------------------------------------------------------
1 |
2 | Vuejs-python brings the concepts of vuejs to Python.
3 | You can write your model/data as a Python object and your HTML UI/view with the very convenient vuejs syntax.
4 | As soon as part of your model changes, all dependent variables are updated and the HTML UI is automatically refreshed.
5 |
6 | The goal is to use not only Python the language but Python the platform (with numpy, system APIs, and other "native" things).
7 |
8 | ## Installation
9 |
10 | ~~~
11 | pip install vuejspython
12 | ~~~
13 |
14 | ## Tiny Example
15 |
16 | You need to create two files: one Python model and an HTML UI.
17 | A good convention (to help tools) is to use the same name, with the `.py` and `.html` extensions, respectively.
18 |
19 |
42 | Fill the radius in the text field: .
43 | (or with
44 | A disk with radius {{ radius }} has an area of {{ area }}.
45 |
46 |
47 |
48 |
49 | ```
50 |
51 |
52 |
53 |
54 | ## Running, option 1: only with Python
55 |
56 | ~~~bash
57 | python3 example.py
58 |
59 | # or a tiny shell function helper
60 | pvue() { (sleep .5;firefox ${1%.*}.html)& python3 ${1%.*}.py;}
61 | pvue example.py
62 | ~~~
63 |
64 | This will give you an address to which you should append your HTML file name, here `example.html`.
65 | In this example, you will visit
66 | (or visit the given address `http://localhost:4260` and click your file).
67 |
68 | NB: you need to stop the command with `Ctrl+C` if you want to run another example.
69 |
70 |
71 | ## Running, option 2: with hot reload on file change
72 |
73 | Here we will start two processes, one for the HTML part (with live reload, and another only for the Python).
74 |
75 | Terminal 1, hosting the HTML files with hot reload:
76 |
77 | ~~~bash
78 | # one-time install
79 | pip install watchdog
80 | npm install -g simple-hot-reload-server
81 | # in terminal 1 (hot html reload, for all files)
82 | hrs .
83 | ~~~
84 | (this gives you the address to open, after appending your file name, e.g., )
85 |
86 | Terminal 2, running the python server
87 |
88 | ~~~bash
89 | # in terminal 2 (start or restart python)
90 | NOSERVE=1 python3 example.py
91 | # OR, for live restart
92 | NOSERVE=1 watchmedo auto-restart --patterns="*.py" python3 example.py
93 | ~~~
94 | NB: `NOSERVE=1` tells vuejspython to not serve the HTML files (it is handled by `hrs` above)
95 |
96 | NB: when changing the .py, a manual browser refresh is still needed, see below for a more complete solution
97 |
98 | ### Helper for complete live reload (live restart for python)
99 |
100 | ~~~bash
101 | pvue() { if test "$1" = open ; then shift ; (sleep 1 ; firefox "http://localhost:8082/${1%.*}.html") & fi; watchmedo auto-restart --patterns="*.py" --ignore-patterns="*/.#*.py" bash -- -c '(sleep .250 ; touch '"${1%.*}"'.html) & python3 '"${1%.*}"'.py' ; }
102 | # Then
103 | pvue example
104 | # OR to also open firefox
105 | pvue open example
106 | # OR some convenient variations
107 | NOSERVE=1 pvue open example
108 | pvue open example.
109 | pvue open example.py
110 | pvue open example.html
111 | # it always runs the file with the .py extension
112 | ~~~
113 |
114 |
115 | ## Other, different projects
116 |
117 | If you're interested only in using Python the language with Vue.js, you can try [brython](http://brython.info/) and the [brython vue demo](http://brython.info/gallery/test_vue.html)
118 |
119 | There are projects that try to help integrating Vue.js with different Python web frameworks. The goal is different: Vuejs-python makes python and vue tightly integrated, in a common, reactive model.
120 |
121 | ----
122 |
123 |
124 | ## Development (TO BE REVIEWED AND UPDATED)
125 |
126 | ### Requirements
127 |
128 | ~~~ bash
129 | pip install aiohttp
130 | pip install websockets
131 | ~~~
132 |
133 | You also need to get a few libraries:
134 |
135 | ~~~
136 | cd vuejspython
137 | ./update-static.sh # or manually download the files
138 | ~~~
139 |
140 | ### Notes
141 |
142 | Currently, the project uses requires some "observable collections", with some modifications.
143 | They are included in the package, in `vuejspython/observablecollections`.
144 | They have been obtained with:
145 |
146 | ~~~ bash
147 | git clone https://github.com/fousteris-dim/Python-observable-collections.git observablecollections
148 | patch -d observablecollections/ < 0001-Local-imports.patch
149 | ~~~
150 |
151 |
152 |
153 | ## Helpers
154 |
155 | ### Simply launch python and open a browser (firefox) at the right address.
156 |
157 | ~~~ bash
158 | # bash function
159 | pvue() { (sleep .5;firefox ${1%.*}.html)& python3 ${1%.*}.py;}
160 |
161 | # examples
162 | pvue example-1
163 | pvue example-1.
164 | pvue example-1.html
165 | pvue example-1.py
166 | ~~~
167 |
168 |
169 | ### OR, to develop with auto-reload.
170 |
171 | ~~~ bash
172 | # one-time install
173 | pip install watchdog
174 | npm install -g simple-hot-reload-server
175 |
176 |
177 | # in terminal 1 (hot html reload, for all files)
178 | hrs .
179 |
180 | # in terminal 2 (start and restart python
181 | pvue() { if test "$1" = open ; then shift ; (sleep 1 ; firefox "http://localhost:8082/${1%.*}.html") & fi; watchmedo auto-restart --patterns="*.py" --ignore-patterns="*/.#*.py" bash -- -c '(sleep .250 ; touch '"${1%.*}"'.html) & python3 '"${1%.*}"'.py' ; }
182 | pvue open example-1
183 | pvue example-1
184 | # the first opens firefox initially
185 | ~~~
186 |
187 |
188 | ## Pypi stuff
189 |
190 | ~~~
191 | python3 -m pip install --upgrade setuptools wheel
192 | python3 -m pip install --upgrade twine
193 |
194 | # update the version number in setup.py and then
195 | rm -rf dist/
196 | python3 setup.py sdist bdist_wheel
197 | python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
198 | # OR: python3 -m twine upload dist/*
199 |
200 | python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps vuejspython
201 |
202 | pip uninstall vuejspython
203 |
204 | python3 -m pip install .. ; ll $VENV/lib/python3.6/site-packages/vuejspython
205 | ~~~
206 |
207 |
208 | ## TODO
209 |
210 | - see why example-8 is slow with the python-only server
211 | - test atomic in components
212 | - make it an all-components (no too-special ROOT', with also js that tells what class and package/file (import everything manually in a main.py if not easy) is the root -> this way we can run a single python and have multiple demos
213 | - have a clean solution for the observable collections (integrate and clean minimal code or find another lib)
214 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | If you're looking for "Vuejs-python that brings the concepts of vuejs to Python", see our V0 branch (and readme, and V0.* on pypi).
3 |
4 | The goal of vuejs-python (starting from V1) is to
5 | - easily run standalone Vue.js components / micro-apps,
6 | - give them access to the working directory,
7 | - allow (unsafe) extensions to be written in Python (including numpy, local resource access, etc)
8 |
9 |
10 | ## Installation
11 |
12 | ~~~
13 | pip install vuejspython
14 | ~~~
15 |
16 | ## Usage
17 |
18 | ~~~
19 | vjspy [--trust-python] [--port=...] [--host=...] myfile.vue more arbitrary parameters
20 | ~~~
21 |
22 |
23 | You can run the bundled tools using their `:` prefixed names instead of the vue file.
24 | These files are in https://github.com/twitwi/vuejs-python/tree/main/vuejspython/builtin
25 |
26 | Here are some example usage, that can be followed as a tutorial:
27 |
28 | ~~~
29 | vjspy :create-demo-files demo
30 | vjspy :view-file demo/file1.txt
31 | vjspy :edit-file demo/file1.txt
32 | vjspy --trust-python :rotate-files demo/file*.txt
33 | vjspy :toggle-exam demo/exam/*
34 |
35 | # hosting the current folder with a video player
36 | vjspy :serve-videos
37 | ~~~
38 |
39 | ## Snippets
40 |
41 | ### HTML head
42 |
43 | To add something in the HTML head (change title, icon, load library, etc):
44 |
45 | ~~~html
46 |
47 |
48 | View File
49 |
50 |
52 |
53 | ...
54 |
55 | ~~~
56 |
57 | ### Accessing Vue
58 |
59 | To import elements from the bundled Vue (you can remove `lang="ts"` to use plain js, and setup to use a traditional component writing):
60 |
61 | ~~~html
62 |
66 | ~~~
67 |
68 | ### Accessing files
69 |
70 | To use the custom filesystem API ([asynchronously](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Async_JS/Promises)):
71 |
72 | ~~~javascript
73 |
106 |
107 |
113 | ~~~
114 |
115 | See also the [rotate-files example](https://github.com/twitwi/vuejs-python/tree/main/vuejspython/builtin/rotate-files.vue) that uses command line arguments (in python) too.
116 |
117 |
118 | ### Handling url hash
119 |
120 | ~~~javascript
121 | {
125 | // also triggers on first load (with empty hash or the hash from the initial URL)
126 | if (h !== '') {
127 | alert('you changed the address to '+h)
128 | }
129 | })
130 |
131 | function showAbout() {
132 | ...
133 | setHash('about')
134 | }
135 | ~~~
136 |
137 |
138 |
139 | ----
140 |
141 |
142 |
143 |
144 | ## Pypi stuff
145 |
146 | (in a clean clone, to be sure that not too much thing are copied)
147 |
148 | ~~~
149 | python3 -m pip install --upgrade setuptools wheel
150 | python3 -m pip install --upgrade twine
151 |
152 |
153 | # update the version number in setup.py and then
154 | ./update-static.sh
155 | rm -rf dist/
156 | python3 setup.py sdist bdist_wheel
157 | python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
158 | # OR: python3 -m twine upload dist/*
159 |
160 | python3 -m pip install --index-url https://test.pypi.org/simple/ --upgrade --no-deps vuejspython
161 | # OR: python3 -m pip install --upgrade --no-deps vuejspython
162 |
163 | pip uninstall vuejspython
164 |
165 | python3 -m pip install .. ; ll $VENV/lib/python3.6/site-packages/vuejspython
166 | ~~~
167 |
168 |
169 |
170 | ## TODO
171 |
172 |
173 | - [ ] maybe integrate zod?
174 | - [ ] doc that some thing are bunlded or with e.g. /.runner/builtin/diff.min.js ... consider e.g. #diff in addition for these... yes, like the #fsapi (which is built-in too)
175 | - [ ] example: exam, diff does not update/clear on save
176 | - [ ] Allow --online to get latest libs from cdn
177 | - [ ] Allow --open-browser to open the file
178 | - [ ] Allow opening an existing instance if the port is taken (already running)
179 | - [ ] Allow a random port
180 | - [ ] Warn if some python but no --trust-python (and neither --no-pyton) and show the updated command
181 | - [ ] Allow some config section, e.g. with prefered port etc
182 | - [ ] Update build system... python setup.py is deprecated
183 | - [ ] When trust-python, expose an api to run shell commands too (maybe proto in trailtools)
184 | - [ ] consider integration of .quit (from trailtools logdown / sport)
185 | - [ ] an eject command to get the source of a bultin
186 | - [ ] a @pkg/exc to allow for running a custom one, e.g. that have been vjspy install github:twitwi/blabla... or rather pip installed! (with maybe a default per package? so just @pkg is ok?)
187 | - [ ] video: allow for a logo
188 | - [ ] video: filter files (e.g. remove extensionless things, vtt too, etc, optionnal, still allow to show all with a checkbox)
189 |
190 | BETTER FS API
191 |
192 | - [ ] Allow --allow-all-files
193 | - [ ] Nicer not-all-recursive listing... for perfs
194 | - [ ] Also add watcher option (need websockets probably, or add a polling e.g. /.changed /.last-change)
195 | - [ ] consider use as vite-based projects too? and/or a version that hosts a build page but allows the fs api etc? and/or an fsapi that works similarly but in vite? see https://github.com/StarLederer/vite-plugin-fs (for inspiration or direct use) or 4y https://github.com/antfu/vite-fs
196 |
197 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read().split('----')[0]
5 |
6 | setuptools.setup(
7 | name="vuejspython",
8 | version="1.0.6",
9 | author="Rémi Emonet",
10 | author_email="remi+242-e2f8@heeere.com",
11 | description="Vuejs runner, with filesystem, and allowing python extension (e.g., to leverage numpy)",
12 | long_description=long_description,
13 | long_description_content_type="text/markdown",
14 | url="https://github.com/twitwi/vuejs-python/",
15 | install_requires=['fastapi', 'uvicorn'],
16 | packages=setuptools.find_packages(),
17 | package_data={
18 | 'vuejspython': ['index.html', '*.js', 'builtin/*'],
19 | },
20 | entry_points = {
21 | 'console_scripts': [
22 | 'vjspy = vuejspython.run:cli',
23 | ],
24 | },
25 | classifiers=[
26 | "Programming Language :: Python :: 3",
27 | "License :: OSI Approved :: MIT License",
28 | "Operating System :: OS Independent",
29 | ],
30 | )
31 |
--------------------------------------------------------------------------------
/update-static.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cat < /dev/null
4 |
113 |
--------------------------------------------------------------------------------
/vuejspython/builtin/diff.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | diff v5.1.0
4 |
5 | Software License Agreement (BSD License)
6 |
7 | Copyright (c) 2009-2015, Kevin Decker
8 |
9 | All rights reserved.
10 |
11 | Redistribution and use of this software in source and binary forms, with or without modification,
12 | are permitted provided that the following conditions are met:
13 |
14 | * Redistributions of source code must retain the above
15 | copyright notice, this list of conditions and the
16 | following disclaimer.
17 |
18 | * Redistributions in binary form must reproduce the above
19 | copyright notice, this list of conditions and the
20 | following disclaimer in the documentation and/or other
21 | materials provided with the distribution.
22 |
23 | * Neither the name of Kevin Decker nor the names of its
24 | contributors may be used to endorse or promote products
25 | derived from this software without specific prior
26 | written permission.
27 |
28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
29 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
30 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
34 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 | @license
37 | */
38 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e=e||self).Diff={})}(this,function(e){"use strict";function t(){}t.prototype={diff:function(u,a,e){var n=2=c&&h<=i+1)return d([{value:this.join(a),count:a.length}]);function o(){for(var e,n=-1*p;n<=p;n+=2){var t=void 0,r=v[n-1],i=v[n+1],o=(i?i.newPos:0)-n;r&&(v[n-1]=void 0);var l=r&&r.newPos+1=c&&h<=o+1)return d(function(e,n,t,r,i){for(var o=0,l=n.length,s=0,u=0;oe.length?t:e}),d.value=e.join(f)):d.value=e.join(t.slice(s,s+d.count)),s+=d.count,d.added||(u+=d.count))}var c=n[l-1];1e.length)&&(n=e.length);for(var t=0,r=new Array(n);t=c.length-2&&u.length<=d.context&&(i=/\n$/.test(a),o=/\n$/.test(f),l=0==u.length&&g.length>r.oldLines,!i&&l&&0e.length)return!1;for(var t=0;t"):i.removed&&t.push(""),t.push((n=i.value,n.replace(/&/g,"&").replace(//g,">").replace(/"/g,"""))),i.added?t.push(""):i.removed&&t.push("")}return t.join("")},e.createPatch=function(e,n,t,r,i,o){return y(e,e,n,t,r,i,o)},e.createTwoFilesPatch=y,e.diffArrays=function(e,n,t){return g.diff(e,n,t)},e.diffChars=function(e,n,t){return r.diff(e,n,t)},e.diffCss=function(e,n,t){return f.diff(e,n,t)},e.diffJson=function(e,n,t){return p.diff(e,n,t)},e.diffLines=L,e.diffSentences=function(e,n,t){return a.diff(e,n,t)},e.diffTrimmedLines=function(e,n,t){var r=i(t,{ignoreWhitespace:!0});return u.diff(e,n,r)},e.diffWords=function(e,n,t){return t=i(t,{ignoreWhitespace:!0}),s.diff(e,n,t)},e.diffWordsWithSpace=function(e,n,t){return s.diff(e,n,t)},e.merge=function(e,n,t){e=b(e,t),n=b(n,t);var r={};(e.index||n.index)&&(r.index=e.index||n.index),(e.newFileName||n.newFileName)&&(F(e)?F(n)?(r.oldFileName=N(r,e.oldFileName,n.oldFileName),r.newFileName=N(r,e.newFileName,n.newFileName),r.oldHeader=N(r,e.oldHeader,n.oldHeader),r.newHeader=N(r,e.newHeader,n.newHeader)):(r.oldFileName=e.oldFileName,r.newFileName=e.newFileName,r.oldHeader=e.oldHeader,r.newHeader=e.newHeader):(r.oldFileName=n.oldFileName||e.oldFileName,r.newFileName=n.newFileName||e.newFileName,r.oldHeader=n.oldHeader||e.oldHeader,r.newHeader=n.newHeader||e.newHeader)),r.hunks=[];for(var i=0,o=0,l=0,s=0;i
2 |
3 | Edit File
4 |
5 |