Initial implementation of Deuthon interpreter
Introduced the Deuthon language interpreter for parsing and executing code written with German-like syntax in Python. Added infrastructure files, including a .gitignore, LICENSE, and pyproject.toml, defining the project setup and metadata. Implemented core modules to handle the language-specific logic, such as token transformations, custom import hooks, and wrappers for standard library modules with German names. This foundation enables the development and testing of Deuthon scripts, laying the groundwork for future enhancements and community contributions.
This commit is contained in:
commit
6add03fe4e
27 changed files with 563 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
venv/
|
||||||
|
*.pyc
|
||||||
|
__pycache__/
|
||||||
|
.vscode/
|
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2023 Kumi Mitterer <deuthon@kumi.email>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
0
README.md
Normal file
0
README.md
Normal file
26
pyproject.toml
Normal file
26
pyproject.toml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "deuthon"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = [
|
||||||
|
{ name="Kumi Mitterer", email="deuthon@kumi.email" },
|
||||||
|
]
|
||||||
|
description = "Deuthon interpreter written in Python"
|
||||||
|
readme = "README.md"
|
||||||
|
license = { file="LICENSE" }
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
classifiers = [
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
deuthon = "deuthon.__main__:main"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
"Homepage" = "https://kumig.it/kumitterer/deuthon"
|
||||||
|
"Bug Tracker" = "https://kumig.it/kumitterer/deuthon/issues"
|
0
src/deuthon/__init__.py
Normal file
0
src/deuthon/__init__.py
Normal file
70
src/deuthon/__main__.py
Executable file
70
src/deuthon/__main__.py
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import tokenize
|
||||||
|
import pathlib
|
||||||
|
import setuptools
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
from deuthon.transformer import parse_german_code, prepare_builtin_overrides
|
||||||
|
from deuthon.importer import install_deuthon_importer, import_base
|
||||||
|
from deuthon.interpreter import interpreter
|
||||||
|
|
||||||
|
import deuthon.base
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = ArgumentParser()
|
||||||
|
args.add_argument("file", default="", nargs="?")
|
||||||
|
args.add_argument("--version", "-V", action="version", version="Deuthon 0.1.0")
|
||||||
|
args = args.parse_args()
|
||||||
|
|
||||||
|
prepare_builtin_overrides()
|
||||||
|
install_deuthon_importer(pathlib.Path(__file__).parent / "wrappers")
|
||||||
|
import_base(pathlib.Path(__file__).parent / "base")
|
||||||
|
|
||||||
|
if args.file:
|
||||||
|
with open(args.file) as f:
|
||||||
|
german_code = f.read()
|
||||||
|
|
||||||
|
python_code = parse_german_code(german_code)
|
||||||
|
|
||||||
|
code_object = compile(
|
||||||
|
python_code,
|
||||||
|
pathlib.Path(args.file).absolute(),
|
||||||
|
"exec",
|
||||||
|
dont_inherit=True,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
exec(code_object, {"__file__": pathlib.Path(args.file).absolute()})
|
||||||
|
except Ausnahme as e:
|
||||||
|
# Extract traceback information, excluding frames related to the interpreter
|
||||||
|
tb = e.__traceback__
|
||||||
|
while tb is not None:
|
||||||
|
if __file__ in tb.tb_frame.f_code.co_filename:
|
||||||
|
# Remove this frame from the traceback
|
||||||
|
if tb.tb_next is None:
|
||||||
|
# Reached the end of the traceback linked list; remove reference to this frame
|
||||||
|
tb = None
|
||||||
|
else:
|
||||||
|
# Skip this frame and link the previous frame to the next one
|
||||||
|
tb = tb.tb_next
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Format and print the modified traceback
|
||||||
|
formatted_tb = "".join(traceback.format_exception(type(e), e, tb))
|
||||||
|
print(formatted_tb, file=sys.stderr, end="")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
interpreter()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
0
src/deuthon/base/__init__.deu
Normal file
0
src/deuthon/base/__init__.deu
Normal file
2
src/deuthon/base/ausnahme.deu
Normal file
2
src/deuthon/base/ausnahme.deu
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
GrundAusnahme = BaseException
|
||||||
|
Ausnahme = Exception
|
1
src/deuthon/base/bedingungen.deu
Normal file
1
src/deuthon/base/bedingungen.deu
Normal file
|
@ -0,0 +1 @@
|
||||||
|
istinstanz = isinstance
|
80
src/deuthon/dictionary/__init__.py
Normal file
80
src/deuthon/dictionary/__init__.py
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
from pathlib import Path
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
dictionary = {
|
||||||
|
# Conditionals
|
||||||
|
"wenn": "if",
|
||||||
|
"sonstwenn": "elif",
|
||||||
|
"falls": "if",
|
||||||
|
"sonstfalls": "elif",
|
||||||
|
"sonst": "else",
|
||||||
|
"anderenfalls": "else",
|
||||||
|
|
||||||
|
# Booleans / Truth Values / Logic
|
||||||
|
"Wahr": "True",
|
||||||
|
"Falsch": "False",
|
||||||
|
"Keines": "None",
|
||||||
|
"Nichts": "None",
|
||||||
|
"nicht": "not",
|
||||||
|
"und": "and",
|
||||||
|
"oder": "or",
|
||||||
|
|
||||||
|
# Imports / Contexts
|
||||||
|
"importiere": "import",
|
||||||
|
"von": "from",
|
||||||
|
"aus": "from",
|
||||||
|
"als": "as",
|
||||||
|
"mit": "with",
|
||||||
|
"öffne": "open",
|
||||||
|
|
||||||
|
# Loops
|
||||||
|
"für": "for",
|
||||||
|
"von": "in",
|
||||||
|
"während": "while",
|
||||||
|
"solange": "while",
|
||||||
|
"bis": "until",
|
||||||
|
|
||||||
|
# Try / Except
|
||||||
|
"versuche": "try",
|
||||||
|
"außer": "except",
|
||||||
|
"fange": "except",
|
||||||
|
"schließlich": "finally",
|
||||||
|
|
||||||
|
# Base Types
|
||||||
|
"wahrheitswert": "bool",
|
||||||
|
"zeichenkette": "str",
|
||||||
|
"ganzzahl": "int",
|
||||||
|
"fließkommazahl": "float",
|
||||||
|
"liste": "list",
|
||||||
|
"tupel": "tuple",
|
||||||
|
"wörterbuch": "dict",
|
||||||
|
"menge": "set",
|
||||||
|
"gefrorenemenge": "frozenset",
|
||||||
|
"datei": "file",
|
||||||
|
|
||||||
|
# Base Functions
|
||||||
|
"drucke": "print",
|
||||||
|
"Bereich": "range",
|
||||||
|
|
||||||
|
# Function control flow
|
||||||
|
"definiere": "def",
|
||||||
|
"klasse": "class",
|
||||||
|
"weiter": "continue",
|
||||||
|
"passe": "pass",
|
||||||
|
"gib": "yield",
|
||||||
|
"wirf": "raise",
|
||||||
|
"stellesicher": "assert",
|
||||||
|
"sicherstelle": "assert",
|
||||||
|
"lösche": "del",
|
||||||
|
"zurück": "return",
|
||||||
|
"gibzurück": "return",
|
||||||
|
"brichab": "break",
|
||||||
|
|
||||||
|
# Globals, locals, and nonlocals
|
||||||
|
"__datei__": "__file__",
|
||||||
|
"__klasse__": "__class__",
|
||||||
|
|
||||||
|
# Other things
|
||||||
|
"poppen": "pop",
|
||||||
|
"dekodieren": "decode",
|
||||||
|
}
|
157
src/deuthon/importer.py
Normal file
157
src/deuthon/importer.py
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import importlib.abc
|
||||||
|
import importlib.util
|
||||||
|
import importlib.machinery
|
||||||
|
import os
|
||||||
|
import tokenize
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import builtins
|
||||||
|
|
||||||
|
from .transformer import parse_german_code
|
||||||
|
|
||||||
|
|
||||||
|
class DeuthonSourceLoader(importlib.machinery.SourceFileLoader):
|
||||||
|
def create_module(self, spec):
|
||||||
|
# Creating the module instance. The import system will then call exec_module.
|
||||||
|
module = super().create_module(spec)
|
||||||
|
if module is not None:
|
||||||
|
# Set __package__ if not already set
|
||||||
|
if module.__package__ is None:
|
||||||
|
module.__package__ = (
|
||||||
|
spec.name
|
||||||
|
if spec.submodule_search_locations is None
|
||||||
|
else spec.parent
|
||||||
|
)
|
||||||
|
return module
|
||||||
|
|
||||||
|
def exec_module(self, module):
|
||||||
|
# The module's __file__ attribute must be set prior to the code execution to support relative imports.
|
||||||
|
module.__file__ = self.get_filename(module.__name__)
|
||||||
|
# Call the parent method to execute the module body
|
||||||
|
super().exec_module(module)
|
||||||
|
|
||||||
|
def source_to_code(self, data, path, *, _optimize=-1):
|
||||||
|
reader = tokenize.open(path)
|
||||||
|
try:
|
||||||
|
encoding = reader.encoding
|
||||||
|
source_data = reader.read()
|
||||||
|
finally:
|
||||||
|
reader.close()
|
||||||
|
|
||||||
|
transpiled_code = parse_german_code(source_data)
|
||||||
|
return compile(
|
||||||
|
transpiled_code, path, "exec", dont_inherit=True, optimize=_optimize
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DeuthonModuleFinder(importlib.abc.MetaPathFinder):
|
||||||
|
def __init__(self, wrappers_directory, extension=".deu"):
|
||||||
|
self.wrappers_directory = wrappers_directory
|
||||||
|
self.extension = extension
|
||||||
|
|
||||||
|
def find_spec(self, fullname, path, target=None):
|
||||||
|
# Check inside the wrappers directory first
|
||||||
|
deu_wrapper_path = os.path.join(
|
||||||
|
self.wrappers_directory, fullname + self.extension
|
||||||
|
)
|
||||||
|
if os.path.isfile(deu_wrapper_path):
|
||||||
|
loader = DeuthonSourceLoader(fullname, deu_wrapper_path)
|
||||||
|
spec = importlib.util.spec_from_loader(
|
||||||
|
fullname, loader, origin=deu_wrapper_path
|
||||||
|
)
|
||||||
|
return spec
|
||||||
|
|
||||||
|
# Check for a .py wrapper
|
||||||
|
wrapper_path = os.path.join(self.wrappers_directory, fullname + ".py")
|
||||||
|
if os.path.isfile(wrapper_path):
|
||||||
|
return importlib.util.spec_from_file_location(fullname, wrapper_path)
|
||||||
|
|
||||||
|
# Check for a wrapper package
|
||||||
|
deu_wrapper_path = self._find_deu_file(fullname, [self.wrappers_directory])
|
||||||
|
if deu_wrapper_path:
|
||||||
|
loader = DeuthonSourceLoader(fullname, deu_wrapper_path)
|
||||||
|
spec = importlib.util.spec_from_loader(
|
||||||
|
fullname, loader, origin=deu_wrapper_path
|
||||||
|
)
|
||||||
|
return spec
|
||||||
|
|
||||||
|
# If it's not a wrapper, look for a .deu file
|
||||||
|
deu_path = self._find_deu_file(fullname, path)
|
||||||
|
if deu_path:
|
||||||
|
loader = DeuthonSourceLoader(fullname, deu_path)
|
||||||
|
spec = importlib.util.spec_from_loader(fullname, loader, origin=deu_path)
|
||||||
|
if self._is_package(deu_path):
|
||||||
|
spec.submodule_search_locations = [os.path.dirname(deu_path)]
|
||||||
|
return spec
|
||||||
|
|
||||||
|
# Neither .deu file nor wrapper found
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _is_package(self, path):
|
||||||
|
# Determine if the path is a package by checking for an __init__.deu file
|
||||||
|
return os.path.isdir(path) and os.path.isfile(
|
||||||
|
os.path.join(path, "__init__.deu")
|
||||||
|
)
|
||||||
|
|
||||||
|
def _find_deu_file(self, fullname, path=None):
|
||||||
|
# Determine search paths
|
||||||
|
if not path:
|
||||||
|
# If 'path' is not provided, create a search path
|
||||||
|
# Including the current directory and any DEUTHON_PATH directories
|
||||||
|
path = ["."]
|
||||||
|
deuthon_path = os.environ.get("DEUTHON_PATH")
|
||||||
|
if deuthon_path:
|
||||||
|
path.extend(deuthon_path.split(os.pathsep))
|
||||||
|
|
||||||
|
# The base name for the file we're trying to find will be the last component of 'fullname'
|
||||||
|
# e.g., for 'testmodul.submodul.test', we want to end up with 'test.deu'
|
||||||
|
module_basename = (
|
||||||
|
fullname.rpartition(".")[-1] + self.extension
|
||||||
|
) # e.g., 'test.deu'
|
||||||
|
|
||||||
|
for entry in path:
|
||||||
|
module_full_path = os.path.join(
|
||||||
|
entry, fullname.replace(".", "/") + self.extension
|
||||||
|
)
|
||||||
|
init_full_path = os.path.join(
|
||||||
|
entry, fullname.replace(".", "/"), "__init__" + self.extension
|
||||||
|
)
|
||||||
|
|
||||||
|
if os.path.isfile(
|
||||||
|
module_full_path
|
||||||
|
): # Regular module (or top-level package)
|
||||||
|
return module_full_path
|
||||||
|
|
||||||
|
if os.path.isdir(os.path.dirname(init_full_path)) and os.path.isfile(
|
||||||
|
init_full_path
|
||||||
|
): # Package
|
||||||
|
return init_full_path
|
||||||
|
|
||||||
|
return None # No module or package found
|
||||||
|
|
||||||
|
|
||||||
|
def install_deuthon_importer(wrappers_directory):
|
||||||
|
deuthon_finder = DeuthonModuleFinder(wrappers_directory)
|
||||||
|
sys.meta_path.insert(0, deuthon_finder)
|
||||||
|
|
||||||
|
|
||||||
|
def import_base(base_directory):
|
||||||
|
# Find all .deu files in the given directory
|
||||||
|
for filename in os.listdir(base_directory):
|
||||||
|
if filename.endswith(".deu"):
|
||||||
|
# Construct module name from file name
|
||||||
|
module_name = filename[:-4] # Remove .deu extension
|
||||||
|
module_path = os.path.join(base_directory, filename)
|
||||||
|
|
||||||
|
# Load the module using DeuthonSourceLoader
|
||||||
|
loader = DeuthonSourceLoader(module_name, module_path)
|
||||||
|
spec = importlib.util.spec_from_loader(
|
||||||
|
module_name, loader, origin=module_path
|
||||||
|
)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
loader.exec_module(module)
|
||||||
|
|
||||||
|
# Add all names that don't start with an underscore to builtins
|
||||||
|
for name in dir(module):
|
||||||
|
if not name.startswith("_"):
|
||||||
|
setattr(builtins, name, getattr(module, name))
|
11
src/deuthon/interpreter.py
Normal file
11
src/deuthon/interpreter.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from .transformer import parse_german_code
|
||||||
|
|
||||||
|
def interpreter():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
german_code = input('>>> ')
|
||||||
|
except EOFError:
|
||||||
|
break
|
||||||
|
|
||||||
|
python_code = parse_german_code(german_code)
|
||||||
|
exec(python_code)
|
37
src/deuthon/transformer.py
Normal file
37
src/deuthon/transformer.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import ast
|
||||||
|
import tokenize
|
||||||
|
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from .dictionary import dictionary
|
||||||
|
|
||||||
|
def translate_german_keywords(tokens):
|
||||||
|
for token in tokens:
|
||||||
|
# Translate German keywords to English
|
||||||
|
if token.type == tokenize.NAME and token.string in dictionary:
|
||||||
|
yield token._replace(string=dictionary[token.string])
|
||||||
|
else:
|
||||||
|
yield token
|
||||||
|
|
||||||
|
def parse_german_code(german_code):
|
||||||
|
# Convert the German code into bytes for tokenization
|
||||||
|
bytes_code = bytes(german_code, 'utf-8')
|
||||||
|
|
||||||
|
# Tokenize the German code
|
||||||
|
tokens = tokenize.tokenize(BytesIO(bytes_code).readline)
|
||||||
|
|
||||||
|
# Translate German tokens to their English (Python) counterparts
|
||||||
|
english_tokens = translate_german_keywords(tokens)
|
||||||
|
|
||||||
|
# Detokenize back to a code string in English/Python
|
||||||
|
python_code_str = tokenize.untokenize(english_tokens).decode('utf-8')
|
||||||
|
|
||||||
|
# Return the compiled Python code object
|
||||||
|
return python_code_str
|
||||||
|
|
||||||
|
def prepare_builtin_overrides():
|
||||||
|
import sys
|
||||||
|
|
||||||
|
original_json = sys.modules["json"]
|
||||||
|
sys.modules["sysjson"] = original_json
|
||||||
|
del sys.modules["json"]
|
1
src/deuthon/wrappers/ervbib/__init__.deu
Normal file
1
src/deuthon/wrappers/ervbib/__init__.deu
Normal file
|
@ -0,0 +1 @@
|
||||||
|
importiere urllib
|
27
src/deuthon/wrappers/ervbib/anfrage.deu
Normal file
27
src/deuthon/wrappers/ervbib/anfrage.deu
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
importiere urllib.request
|
||||||
|
importiere http.client
|
||||||
|
|
||||||
|
importiere htüp.kundin
|
||||||
|
|
||||||
|
definiere Anfrage(erv, *argumente, **swargumente):
|
||||||
|
kopfzeilen = swargumente.get("kopfzeilen", {})
|
||||||
|
|
||||||
|
wenn "kopfzeilen" in swargumente:
|
||||||
|
lösche swargumente["kopfzeilen"]
|
||||||
|
|
||||||
|
wenn "benutzer_agent" in swargumente:
|
||||||
|
kopfzeilen["User-Agent"] = swargumente["benutzer_agent"]
|
||||||
|
lösche swargumente["benutzer_agent"]
|
||||||
|
|
||||||
|
wenn kopfzeilen:
|
||||||
|
swargumente["headers"] = kopfzeilen
|
||||||
|
|
||||||
|
gibzurück urllib.request.Request(erv, *argumente, **swargumente)
|
||||||
|
|
||||||
|
definiere ervöffnen(*argumente, **swargumente):
|
||||||
|
antwort = urllib.request.urlopen(*argumente, **swargumente)
|
||||||
|
|
||||||
|
wenn istinstanz(antwort, http.client.HTTPResponse):
|
||||||
|
antwort.__klasse__ = htüp.kundin.HTÜPAntwort
|
||||||
|
|
||||||
|
gibzurück antwort
|
1
src/deuthon/wrappers/htüp/__init__.deu
Normal file
1
src/deuthon/wrappers/htüp/__init__.deu
Normal file
|
@ -0,0 +1 @@
|
||||||
|
importiere http
|
9
src/deuthon/wrappers/htüp/kundin.deu
Normal file
9
src/deuthon/wrappers/htüp/kundin.deu
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
importiere http.client
|
||||||
|
|
||||||
|
klasse HTÜPAntwort(http.client.HTTPResponse):
|
||||||
|
definiere __init__(selbst, *argumente, **swargumente):
|
||||||
|
super().__init__(*argumente, **swargumente)
|
||||||
|
|
||||||
|
definiere lesen(selbst, *argumente, **swargumente):
|
||||||
|
return super().read(*argumente, **swargumente)
|
||||||
|
|
3
src/deuthon/wrappers/importbib.deu
Normal file
3
src/deuthon/wrappers/importbib.deu
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
importiere importlib
|
||||||
|
|
||||||
|
importiere_modul = importlib.import_module
|
6
src/deuthon/wrappers/json.deu
Normal file
6
src/deuthon/wrappers/json.deu
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
importiere sysjson
|
||||||
|
|
||||||
|
laden = sysjson.load
|
||||||
|
ladenz = sysjson.loads
|
||||||
|
abladen = sysjson.dump
|
||||||
|
abladenz = sysjson.dumps
|
24
src/deuthon/wrappers/zeichenkette.deu
Normal file
24
src/deuthon/wrappers/zeichenkette.deu
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
importiere string
|
||||||
|
|
||||||
|
klasse Formatierer(string.Formatter):
|
||||||
|
def __init__(selbst, *argumente, **swargumente):
|
||||||
|
super().__init__(*argumente, **swargumente)
|
||||||
|
|
||||||
|
def formatiere(selbst, formatstring, *argumente, **swargumente):
|
||||||
|
gibzurück super().format(formatstring, *argumente, **swargumente)
|
||||||
|
|
||||||
|
klasse Vorlage(string.Template):
|
||||||
|
def __init__(selbst, *argumente, **swargumente):
|
||||||
|
super().__init__(*argumente, **swargumente)
|
||||||
|
|
||||||
|
ascii_buchstaben = string.ascii_letters
|
||||||
|
ascii_kleinbuchstaben = string.ascii_lowercase
|
||||||
|
ascii_großbuchstaben = string.ascii_uppercase
|
||||||
|
ziffern = string.digits
|
||||||
|
hexadezimalziffern = string.hexdigits
|
||||||
|
oktalziffern = string.octdigits
|
||||||
|
druckbar = string.printable
|
||||||
|
leerzeichen = string.whitespace
|
||||||
|
punktuation = string.punctuation
|
||||||
|
|
||||||
|
kapitalisiere_wörter = string.capwords
|
4
src/deuthon/wrappers/zeit.deu
Normal file
4
src/deuthon/wrappers/zeit.deu
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
importiere time
|
||||||
|
|
||||||
|
schlafe = time.sleep
|
||||||
|
zeit = time.time
|
18
src/deuthon/wrappers/zufall.deu
Normal file
18
src/deuthon/wrappers/zufall.deu
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
importiere random
|
||||||
|
|
||||||
|
klasse SystemZufall(random.SystemRandom):
|
||||||
|
def __init__(selbst, *argumente, **swargumente):
|
||||||
|
super().__init__(*argumente, **swargumente)
|
||||||
|
|
||||||
|
def besamen(selbst, *argumente, **swargumente):
|
||||||
|
gibzurück selbst.seed(*argumente, **swargumente)
|
||||||
|
|
||||||
|
def zufallsganzzahl(selbst, a, b):
|
||||||
|
gibzurück selbst.randint(a, b)
|
||||||
|
|
||||||
|
def zufall(selbst):
|
||||||
|
gibzurück selbst.random()
|
||||||
|
|
||||||
|
zufallsganzzahl = random.randint
|
||||||
|
zufall = random.random
|
||||||
|
besamen = random.seed
|
9
tests/ervbib_json.deu
Normal file
9
tests/ervbib_json.deu
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
importiere ervbib.anfrage
|
||||||
|
importiere json
|
||||||
|
|
||||||
|
anfrage = ervbib.anfrage.Anfrage(
|
||||||
|
erv="https://geek-jokes.sameerkumar.website/api?format=json",
|
||||||
|
benutzer_agent="ERV-Test/1.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
drucke(json.ladenz(ervbib.anfrage.ervöffnen(anfrage).lesen().dekodieren())["joke"])
|
50
tests/test.deu
Normal file
50
tests/test.deu
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Tests für `drucke()` und globale Variablen
|
||||||
|
|
||||||
|
drucke("Starte Tests...")
|
||||||
|
drucke(f"Aktuelle Datei: " + str(__datei__))
|
||||||
|
|
||||||
|
# Import-Tests
|
||||||
|
|
||||||
|
aus zufall importiere SystemZufall
|
||||||
|
aus zeit importiere zeit
|
||||||
|
|
||||||
|
importiere testmodul.test
|
||||||
|
importiere testimport
|
||||||
|
|
||||||
|
# Variablen-Tests (Typen, Zuweisungen, etc.)
|
||||||
|
|
||||||
|
länge: ganzzahl = 1
|
||||||
|
|
||||||
|
system_zufall: SystemZufall = SystemZufall()
|
||||||
|
system_zufall.besamen(ganzzahl(zeit()))
|
||||||
|
|
||||||
|
|
||||||
|
# Funktions-Tests (Parameter, Rückgabewerte, etc.)
|
||||||
|
|
||||||
|
definiere hallo_welt(länge: ganzzahl = länge) -> Nichts:
|
||||||
|
global system_zufall
|
||||||
|
für i in Bereich(länge):
|
||||||
|
falls nicht wahrheitswert(system_zufall.zufallsganzzahl(0, 1)) == Wahr:
|
||||||
|
drucke(i, ": Hallo Welt!")
|
||||||
|
anderenfalls:
|
||||||
|
drucke(i, ": Tschüss Welt!")
|
||||||
|
|
||||||
|
drucke(hallo_welt())
|
||||||
|
|
||||||
|
|
||||||
|
# Sicherstellung von Bedingungen
|
||||||
|
|
||||||
|
stellesicher nicht hallo_welt(), "Hallo Welt ist nicht Nichts!"
|
||||||
|
|
||||||
|
|
||||||
|
# Werfen von Ausnahmen
|
||||||
|
|
||||||
|
versuche:
|
||||||
|
wirf Ausnahme("Test")
|
||||||
|
außer Ausnahme als a:
|
||||||
|
drucke(a)
|
||||||
|
|
||||||
|
|
||||||
|
# ERVBib und JSON
|
||||||
|
|
||||||
|
importiere ervbib_json
|
1
tests/testimport.deu
Normal file
1
tests/testimport.deu
Normal file
|
@ -0,0 +1 @@
|
||||||
|
drucke("Hallo aus dem Testimport!")
|
3
tests/testmodul/__init__.deu
Normal file
3
tests/testmodul/__init__.deu
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
drucke("Hallo aus dem Testmodul!")
|
||||||
|
|
||||||
|
import testmodul.test
|
0
tests/testmodul/test.deu
Normal file
0
tests/testmodul/test.deu
Normal file
Loading…
Reference in a new issue