Update project layout
This commit is contained in:
parent
ea70d9278e
commit
b777df7874
15 changed files with 127 additions and 107 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,2 +1 @@
|
||||||
__pycache__/
|
__pycache__/
|
||||||
dist/
|
|
||||||
34
README.md
34
README.md
|
|
@ -1,5 +1,33 @@
|
||||||
# xopp2py
|
# Python interface to Xournal++ (.xopp) file format
|
||||||
|
|
||||||
Python interface to .xopp (Xournal++) files.
|
## Packages
|
||||||
|
|
||||||
The only dependency is Python 3. (developed with Python 3.10)
|
This project contains the following packages, under `src`:
|
||||||
|
- xopp2py
|
||||||
|
- xopp2oml
|
||||||
|
|
||||||
|
### xopp2py
|
||||||
|
|
||||||
|
Python interface to .xopp (Xournal++)
|
||||||
|
|
||||||
|
Dependencies: Python3
|
||||||
|
|
||||||
|
### xopp2oml
|
||||||
|
|
||||||
|
XOPP to OML converter
|
||||||
|
|
||||||
|
Dependencies: Python3, Jinja2, xopp2py
|
||||||
|
|
||||||
|
#### Entry point: xopp2oml.convert
|
||||||
|
|
||||||
|
Python script that takes as input as .xopp file and produces as output an .oml file.
|
||||||
|
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
The tests are not included in the packages themselves, but as a separate script.
|
||||||
|
|
||||||
|
To run the tests, make sure the packages are installed, and run:
|
||||||
|
```
|
||||||
|
python test/run_tests.py
|
||||||
|
```
|
||||||
|
|
|
||||||
12
default.nix
Normal file
12
default.nix
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
pkgs.python3Packages.buildPythonPackage rec {
|
||||||
|
pname = "xopp2py";
|
||||||
|
version = "1.0.0";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
propagatedBuildInputs = [
|
||||||
|
pkgs.python3Packages.jinja2
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
[project]
|
|
||||||
name = "xopp2py"
|
|
||||||
description = "A Python interface to the Xournal++ file format"
|
|
||||||
version = "1.0.0"
|
|
||||||
authors = [
|
|
||||||
{ name="Joeri Exelmans", email="joeri.exelmans@uantwerpen.be" },
|
|
||||||
]
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.10"
|
|
||||||
classifiers = [
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Operating System :: OS Independent",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build-system]
|
|
||||||
requires = ["hatchling"]
|
|
||||||
build-backend = "hatchling.build"
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
"Homepage" = "https://msdl.uantwerpen.be/git/jexelmans/xopp2py"
|
|
||||||
"Bug Tracker" = "https://msdl.uantwerpen.be/git/jexelmans/xopp2py/issues"
|
|
||||||
16
setup.py
Normal file
16
setup.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='xopp2oml',
|
||||||
|
version='1.0.0',
|
||||||
|
|
||||||
|
install_requires=[
|
||||||
|
'jinja2',
|
||||||
|
],
|
||||||
|
|
||||||
|
package_dir={"":"src"},
|
||||||
|
packages=['xopp2py', 'xopp2oml'],
|
||||||
|
|
||||||
|
include_package_data=True,
|
||||||
|
package_data={"xopp2oml": ["template.oml"]},
|
||||||
|
)
|
||||||
15
shell.nix
15
shell.nix
|
|
@ -1,15 +0,0 @@
|
||||||
# Generates a shell from where all the dependencies can be found.
|
|
||||||
|
|
||||||
{ pkgs ? import <nixpkgs> {} }:
|
|
||||||
|
|
||||||
let
|
|
||||||
SOURCE_DIR = builtins.toString ./src;
|
|
||||||
in
|
|
||||||
pkgs.mkShell {
|
|
||||||
buildInputs = [
|
|
||||||
pkgs.python3
|
|
||||||
pkgs.python3Packages.jinja2
|
|
||||||
];
|
|
||||||
|
|
||||||
PYTHONPATH = SOURCE_DIR;
|
|
||||||
}
|
|
||||||
22
src/xopp2oml/convert.py
Normal file
22
src/xopp2oml/convert.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Command-line tool that demonstrates how to use this library.
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import argparse
|
||||||
|
argparser = argparse.ArgumentParser(
|
||||||
|
description = "Python interface for Xournal++ (.xopp) files.")
|
||||||
|
argparser.add_argument('inputfile')
|
||||||
|
argparser.add_argument('-o', '--output', metavar='FILE', nargs=1, help="OML output file. If not specified, output will be printed to stdout.")
|
||||||
|
args = argparser.parse_args() # exits on error
|
||||||
|
|
||||||
|
# Parse .xopp
|
||||||
|
from xopp2py import parser
|
||||||
|
asyntax = parser.parseFile(args.inputfile)
|
||||||
|
|
||||||
|
# Generate OML
|
||||||
|
from xopp2oml import writer
|
||||||
|
if args.output == None:
|
||||||
|
import sys
|
||||||
|
writer.writeOML(asyntax, args.inputfile, "my_xopp", sys.stdout)
|
||||||
|
else:
|
||||||
|
with open(args.output[0], 'wt') as f:
|
||||||
|
writer.writeOML(asyntax, args.inputfile, "my_xopp", f)
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
{%- macro attributes(pageindex, page, layerindex, layer, elementindex, element) -%}
|
{%- macro attributes(pageindex, page, layerindex, layer, elementindex, element) -%}
|
||||||
{%- for key,value in element.attributes.items() %}
|
{%- for key,value in element.attributes.items() %}
|
||||||
ci p{{pageindex}}l{{layerindex}}e{{elementindex}}a{{loop.index}} : xournalpp:XMLAttribute [
|
ci p{{pageindex}}l{{layerindex}}e{{elementindex}}a{{loop.index}} : xopp:XMLAttribute [
|
||||||
xournalpp:hasKey "{{key}}"
|
xopp:hasKey "{{key}}"
|
||||||
xournalpp:hasValue "{{value}}"
|
xopp:hasValue "{{value}}"
|
||||||
xournalpp:ofLayerElement p{{pageindex}}l{{layerindex}}e{{elementindex}}
|
xopp:ofLayerElement p{{pageindex}}l{{layerindex}}e{{elementindex}}
|
||||||
object_diagram:inModel model
|
object_diagram:inModel model
|
||||||
]
|
]
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
@ -11,9 +11,9 @@
|
||||||
|
|
||||||
{%- macro elements(pageindex, page, layerindex, layer) -%}
|
{%- macro elements(pageindex, page, layerindex, layer) -%}
|
||||||
{% for el in layer.elements %}
|
{% for el in layer.elements %}
|
||||||
ci p{{pageindex}}l{{layerindex}}e{{loop.index}} : xournalpp:{{el.__class__.__name__}} [
|
ci p{{pageindex}}l{{layerindex}}e{{loop.index}} : xopp:{{el.__class__.__name__}} [
|
||||||
xournalpp:hasText "{{el.text}}"
|
xopp:hasText "{{el.text}}"
|
||||||
xournalpp:inLayer p{{pageindex}}l{{layerindex}}
|
xopp:inLayer p{{pageindex}}l{{layerindex}}
|
||||||
object_diagram:inModel model
|
object_diagram:inModel model
|
||||||
]
|
]
|
||||||
{{ attributes(pageindex, page, layerindex, layer, loop.index, el) -}}
|
{{ attributes(pageindex, page, layerindex, layer, loop.index, el) -}}
|
||||||
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
{%- macro layers(pageindex, page) -%}
|
{%- macro layers(pageindex, page) -%}
|
||||||
{% for layer in page.layers %}
|
{% for layer in page.layers %}
|
||||||
ci p{{pageindex}}l{{loop.index}} : xournalpp:Layer [
|
ci p{{pageindex}}l{{loop.index}} : xopp:Layer [
|
||||||
xournalpp:inPage p{{pageindex}}
|
xopp:inPage p{{pageindex}}
|
||||||
object_diagram:inModel model
|
object_diagram:inModel model
|
||||||
]
|
]
|
||||||
{{ elements(pageindex, page, loop.index, layer) -}}
|
{{ elements(pageindex, page, loop.index, layer) -}}
|
||||||
|
|
@ -32,13 +32,13 @@
|
||||||
|
|
||||||
{%- macro pages(file) -%}
|
{%- macro pages(file) -%}
|
||||||
{% for page in file.pages -%}
|
{% for page in file.pages -%}
|
||||||
ci p{{loop.index}} : xournalpp:Page [
|
ci p{{loop.index}} : xopp:Page [
|
||||||
xournalpp:hasWidth {{ page.width }}
|
xopp:hasWidth {{ page.width }}
|
||||||
xournalpp:hasHeight {{ page.height }}
|
xopp:hasHeight {{ page.height }}
|
||||||
xournalpp:hasBackgroundType "{{ page.background_type }}"
|
xopp:hasBackgroundType "{{ page.background_type }}"
|
||||||
xournalpp:hasBackgroundColor "{{ page.background_color }}"
|
xopp:hasBackgroundColor "{{ page.background_color }}"
|
||||||
xournalpp:hasBackgroundStyle "{{ page.background_style }}"
|
xopp:hasBackgroundStyle "{{ page.background_style }}"
|
||||||
xournalpp:inFile file
|
xopp:inFile file
|
||||||
object_diagram:inModel model
|
object_diagram:inModel model
|
||||||
]
|
]
|
||||||
{{ layers(loop.index, page) -}}
|
{{ layers(loop.index, page) -}}
|
||||||
|
|
@ -49,17 +49,17 @@
|
||||||
// Generator: https://msdl.uantwerpen.be/git/jexelmans/xopp2py
|
// Generator: https://msdl.uantwerpen.be/git/jexelmans/xopp2py
|
||||||
description <http://flandersmake.be/cdf/description/{{namespace}}#> as {{namespace}} {
|
description <http://flandersmake.be/cdf/description/{{namespace}}#> as {{namespace}} {
|
||||||
|
|
||||||
uses <http://flandersmake.be/cdf/vocabulary/xournalpp#> as xournalpp
|
uses <http://flandersmake.be/cdf/vocabulary/xopp#> as xopp
|
||||||
uses <http://flandersmake.be/cdf/vocabulary/object_diagram#> as object_diagram
|
uses <http://flandersmake.be/cdf/vocabulary/object_diagram#> as object_diagram
|
||||||
|
|
||||||
ci model : xournalpp:Model []
|
ci model : xopp:Model []
|
||||||
|
|
||||||
ci file : xournalpp:File [
|
ci file : xopp:File [
|
||||||
xournalpp:hasCreator "{{ file.creator }}"
|
xopp:hasCreator "{{ file.creator }}"
|
||||||
xournalpp:hasFileVersion {{ file.fileversion }}
|
xopp:hasFileVersion {{ file.fileversion }}
|
||||||
xournalpp:hasTitle "{{ file.title }}"
|
xopp:hasTitle "{{ file.title }}"
|
||||||
{%- if file.preview != None %}
|
{%- if file.preview != None %}
|
||||||
xournalpp:hasPreview "{{ toBase64(file.preview).decode('utf-8') }}"
|
xopp:hasPreview "{{ toBase64(file.preview).decode('utf-8') }}"
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
object_diagram:inModel model
|
object_diagram:inModel model
|
||||||
]
|
]
|
||||||
|
|
@ -9,7 +9,7 @@ def writeOML(xournalFile: abstract_syntax.XournalFile, inputfile:str, namespace:
|
||||||
environment = jinja2.Environment(
|
environment = jinja2.Environment(
|
||||||
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
|
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
|
||||||
|
|
||||||
template = environment.get_template("oml_writer.template")
|
template = environment.get_template("template.oml")
|
||||||
for piece in template.generate(
|
for piece in template.generate(
|
||||||
file=xournalFile,
|
file=xournalFile,
|
||||||
toBase64=base64.b64encode,
|
toBase64=base64.b64encode,
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
# Command-line tool that demonstrates how to use this library.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
argparser = argparse.ArgumentParser(
|
|
||||||
description = "Python interface for Xournal++ (.xopp) files.")
|
|
||||||
argparser.add_argument('filename')
|
|
||||||
argparser.add_argument('--print-oml', action='store_true', help="Convert to OML and print")
|
|
||||||
argparser.add_argument('--write-oml', metavar='FILE', nargs=1, help="Convert to OML and write to file")
|
|
||||||
args = argparser.parse_args() # exits on error
|
|
||||||
|
|
||||||
print(args)
|
|
||||||
|
|
||||||
from xopp2py import parser
|
|
||||||
|
|
||||||
asyntax = parser.parseFile(args.filename)
|
|
||||||
if args.print_oml:
|
|
||||||
from xopp2py_oml import oml_writer
|
|
||||||
import sys
|
|
||||||
oml_writer.writeOML(asyntax, args.filename, "my_xopp", sys.stdout)
|
|
||||||
elif args.write_oml != None:
|
|
||||||
from xopp2py_oml import oml_writer
|
|
||||||
with open(args.write_oml[0], 'wt') as f:
|
|
||||||
oml_writer.writeOML(asyntax, args.filename, "my_xopp", f)
|
|
||||||
21
test/run_tests.py
Normal file
21
test/run_tests.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
from xopp2py import parser, abstract_syntax
|
||||||
|
from xopp2oml import writer
|
||||||
|
import os
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
DATADIR = os.path.join(os.path.dirname(__file__), "test_data")
|
||||||
|
|
||||||
|
class DummyOutput:
|
||||||
|
def write(self, text: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def parse(filename):
|
||||||
|
asyntax = parser.parseFile(os.path.join(DATADIR, filename))
|
||||||
|
writer.writeOML(asyntax, filename, "my_xopp", DummyOutput())
|
||||||
|
|
||||||
|
# Just see if these files parse without throwing an exception :)
|
||||||
|
parse("SmallXournalFile.xopp")
|
||||||
|
parse("TwoHiddenLayers.xopp")
|
||||||
|
|
||||||
|
|
||||||
|
print("Tests passed.")
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
from xopp2py import parser, abstract_syntax
|
|
||||||
from xopp2py_oml import oml_writer
|
|
||||||
import os
|
|
||||||
|
|
||||||
DATADIR = os.path.join(os.path.dirname(__file__), "data")
|
|
||||||
|
|
||||||
class DummyOutput:
|
|
||||||
def write(self, text: str):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def parse(filename):
|
|
||||||
asyntax = parser.parseFile(os.path.join(DATADIR, filename))
|
|
||||||
oml_writer.writeOML(asyntax, filename, "my_xopp", DummyOutput())
|
|
||||||
|
|
||||||
# Just see if these files parse without throwing an exception :)
|
|
||||||
parse("SmallXournalFile.xopp")
|
|
||||||
parse("TwoHiddenLayers.xopp")
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue