A Python library for Maple file format operations, with logging and console color utilities
Project description
:maple_leaf: MapleX :deciduous_tree:
MapleX is a tool set for Maple file format operations, with logging and console color utilities for Python applications.
You can install the package from pip with the following command.
pip install MapleX
Table of Contents
Maple File
Maple is a file system that I created when I was a child. It's like a combination of the INI file and the Jason file. I made this format that is easy to read and write for both humans and machines.
Basic Format
All data before MAPLE\n will be ignored
MAPLE
# Maple data must start with "MAPLE"
*MAPLE_TIME
yyyy/MM/dd HH:mm:ss.fffffff
# Encoded time or optional time in the method parameter
H *STATUS
# File status
ADT yyyy/MM/dd HH:mm:ss.fffffff
RDT yyyy/MM/dd HH:mm:ss.fffffff
CNT {int}
H #*
ADT is the most recent edited time
RDT is the second most recent edited time (before ADT)
CNT is the data count (Optional)
E *#
E
H *Header
# Headers include '*' are system headers
E
H Data Headers
H Sub Data Header
CMT Comments
# This is also a comment
Tags Properties
# Propaties cannot include 'CRLF.'
Tags2 Properties
# You cannot use the same tags in a Header except CMT and NTE in H NOTES
H Sub Data Header
Tags Propaties
# You can use the same tag in the child header,
# which is already used in the parent's header
E
E
H *NOTES NOTES_HEADER
# Note's header
NTE {strimg}
NTE ...
# Note's main strings for the multi-line data
# COMMENTS IN THE "*NOTES" BLOCK WILL BE DELETED WHEN SAVE VALUE!
E
H #*
This is a comment block.
Starts with "H #*"
and ends with "E *#"
E *#
E
H Data Headers2
E
# "\nEOF\n" must be needed for all data
EOF
All datas after "\nEOF\n" will be ignored
Data boundary
- Maple data will start with a line
MAPLE\nand end with\nEOF\n. - Data outside those lines will be ignored.
E.g.:
MAPLE
<MAPLE DATA>
EOF
:warning: Data outside the Maple data could be lost in the future update.
Blocks
- Block starts with
H <Header Name>and ends withE. - Blocks can be nested.
E.g.:
MAPLE
H FOO
H BAR
...<DATA LINES>
E
...<DATA LINES>
E
EOF
Data Lines
- Each data line has a 'tag' in front of the data.
- The string before the very first white space will be treated as a 'tag', and all the data after the white space will be treated as the data.
E.g.: Store ANY DATA with a tag BAR inside the FOO block
MAPLE
H FOO
BAR ANY DATA
E
EOF
Notes (Multi-lined Data)
v2.2.0 or newer
- You can save multi-lined data inside
H *NOTESblock. - You must specify the header when you save notes value.
E.g.:
MAPLE
H *NOTES NOTES_HEADER
NTE YOU CAN SAVE
NTE MULTI-LINED DATA
NTE INSIDE THIS BLOCK
E
EOF
Comments
v2.1.0 or newer
Comment Line
CMTtag line will be ignored as a comment line.- A line that starts with
#is also treated as a comment line.
E.g.:
MAPLE
H DATA
CMT This is a comment line.
#TAG This is also a comment line.
NOTACOMMENT # This cannot be a comment.
E
EOF
Comment Block
- You can write multi-line comments using a comment block that starts with
H #*and ends withE *#.
E.g.:
MAPLE
H #*
THIS IS A COMMENT BLOCK
YOU CAN WRITE
MULTIPLE LINE COMMENTS
E *#
EOF
MapleTree Class
__init__()
class MapleTree(
fileName: str,
tabInd: int = 4,
encrypt: bool = False,
key: bytes | None = None,
createBaseFile: bool = False
)
| Property | Required | Value |
|---|---|---|
fileName |
* | Maple file name |
tabInd |
White space count for indents | |
encrypt |
File encryption | |
key |
Encryption key | |
createBaseFile |
Create empty base file |
__init__ initialize the class and load a Maple file data to the buffer.
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("FileName.mpl")
Open existing Maple file
__init__ will open the Maple file and load data to the buffer.
mapleFile = MapleTree("FileName.mpl")
Change indent size
mapleFile = MapleTree("FileName.mpl", tabInd=4)
mapleFile._saveToFile()
This makes the maple file look like
MAPLE
H FOO
H BAR
<MAPLE DATA LINES>
E
<MAPLE DATA LINES>
E
EOF
If you change the tabInd value
mapleFile = MapleTree("FileName.mpl", tabInd=2)
mapleFile._saveToFile()
This makes the maple file look like
MAPLE
H FOO
H BAR
<MAPLE DATA LINES>
E
<MAPLE DATA LINES>
E
EOF
Create a Base File
You can create an empty base file when you initialize the class instance.
mapleFile = MapleTree("NewFile.mpl", createBaseFile=True)
This creates an empty Maple file if the file NewFile.mpl does not exist.
MAPLE
EOF
File Data Encryption
If encrypt=True, the instance decrypts data when it is read, and encrypts data when it is saved.
You need to specify the byte key when you use encryption, and the file must be encrypted.
:warning: The key must be 32 url-safe base64-encoded bytes
mapleFile = MapleTree("FileName.mpl", encrypt=True, key=key)
You can create an encrypted base file with createBaseFile=True if the file does not exist.
mapleFile = MapleTree("NewFile.mpl", encrypt=True, key=key, createBaseFile=True)
readMapleTag()
def readMapleTag(
tag: str,
*headers: str
) -> str
| Property | Required | Value |
|---|---|---|
tag |
* | Tag to find |
headers |
Headers contains the tag |
readMapleTag returns a data string tagged with the tag in headers and returns None if the tag was not found.
E.g.:
Sample Data (Sample.mpl)
MAPLE
H FOO
H BAR
TAG1 DATA 1
TAG2 DATA 2
E
E
EOF
from maplex import MapleTree
mapleFile = MapleTree("Sample.mpl")
mapleData = mapleFile.readMapleTag("TAG1", "FOO", "BAR")
print(mapleData)
# Outputs "DATA 1"
saveTagLine()
def saveTagLine(
tag: str,
valueStr: str,
willSave: bool,
*headers: str
) -> None
| Property | Required | Value |
|---|---|---|
tag |
* | Target tag |
valueStr |
* | Data value (string) |
willSave |
* | Save to file flag |
headers |
Target headers |
Outdated from v2.2.0
saveValue()
v2.2.0 or newer
def saveValue(
tag: str,
valueString: any,
*headers: str,
**kwargs
) -> bool
| Property | Required | Value |
|---|---|---|
tag |
* | Target tag |
value |
* | Value to save |
headers |
Target headers | |
kwargs |
Keyword arguments |
saveValue saves a value with a tag in a header block specified by the parameter.
- Set
save=Trueto save changes to the file.- Default:
save=False
- Default:
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl", createBaseFile=True)
mapleFile.saveTagLine("TAG", "VALUE", "FOO", save=True)
This code outputs a file contains:
MAPLE
H FOO
TAG VALUE
E
EOF
Update a Buffer Content
If save=False (or not specified), the buffer content will be updated, but no update on physical file content.
E.g.:
mapleFile.saveTagLine("TAG", "NEW VALUE", "FOO")
This code changes the contents on buffer like:
MAPLE
H FOO
TAG NEW VALUE
E
EOF
But the change is NOT being saved in the file.
MAPLE
H FOO
TAG VALUE
E
EOF
Update and Save Changes
If save=True, all the changes to the buffer will be saved.
mapleFile.saveTagLine("BAR", "ANOTHER VALUE", "FOO", save=True)
This code changes the contents in the file like:
MAPLE
H FOO
TAG NEW VALUE
BAR ANOTHER VALUE
E
EOF
Create New Block and Tag
If the block and/or the header(s) specified with the parameters do not exist in the data, the function creates the new header block(s) and the tag and saves the value.
mapleFile.saveTagLine("TAZ", "NEW HEADER AND TAG", "NEW_HEADER")
This code will change the buffer data like:
MAPLE
H FOO
TAG NEW VALUE
BAR ANOTHER VALUE
E
H NEW_HEADER
TAZ NEW HEADER AND TAG
E
EOF
deleteTag()
def deleteTag(
delTag: str,
willSave: bool = False,
*headers: str
) -> bool
| Property | Required | Value |
|---|---|---|
delTag |
* | Tag to delete |
willSave |
Save to file flag | |
headers |
Target headers |
Outdated from v2.2.0
deleteValue()
v2.2.0 or newer
def deleteValue(
delTag: str,
*headers: str,
**kwargs
) -> bool
| Property | Required | Value |
|---|---|---|
delTag |
* | Tag to delete |
headers |
Target headers | |
kwargs |
Keyword arguments |
Delete a tag and its value.
- Set
save=Trueto save changes to the file.- Default:
save=False
- Default:
Sample data: SampleData.mpl
MAPLE
H FOO
BAR DATA 1
BAZ DATA 2
E
EOF
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl")
mapleFile.deleteTag("BAR", "FOO", save=True)
The file data will be changed like:
MAPLE
H FOO
BAZ DATA 2
E
EOF
getTagValueDict()
getTagValueDic(
*headers: str
) -> dict[str, str]
| Property | Required | Value |
|---|---|---|
headers |
Target headers |
Get tags and values in the header block specified with the parameter as a dict.
Sample data: SampleData.mpl
MAPLE
H FOO
BAR DATA 1
BAZ DATA 2
E
EOF
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl")
dataDict = mapleFile.getTagValueDict()
print(dataDict)
# Outputs "{'BAR': 'DATA 1', 'BAZ': 'DATA 2'}"
getTags()
def getTags(
*headers: str
) -> list[str]
| Property | Required | Value |
|---|---|---|
headers |
Target headers |
Get the list of the tags in the header block specified with the parameter.
Sample data: SampleData.mpl
MAPLE
H FOO
BAR DATA 1
BAZ DATA 2
E
EOF
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl")
tagList = mapleFile.getTags()
print(tagList)
# Outputs "['BAR', 'BAZ']"
deleteHeader()
def deleteHeader(
delHead: str,
willSave: bool = False,
*Headers: str
) -> bool
| Property | Required | Value |
|---|---|---|
delHead |
* | Deleting header |
willSave |
Save to file flag | |
Headers |
Target headers |
Outdated from v2.2.0
removeHeader()
v2.2.0 or newer
def removeHeader(
delHead: str,
*headers: str,
**kwargs
) -> bool
| Property | Required | Value |
|---|---|---|
delHead |
* | Deleting header |
headers |
Target headers | |
kwargs |
Keyword arguments |
This deletes an entire header block and its associated data, including child blocks.
- Set
save=Truefor save data to the file.- Default:
save=False
- Default:
Sample data: SampleData.mpl
MAPLE
H FOO
BAR DATA 1
H BAZ
QUX DATA 2
E
E
H QUUX
CORGE DATA 3
E
EOF
E.g.:
from maplex import MapleTree
mapleTree = MapleTree("SampleData.mpl")
mapleTree.deleteHeader("FOO", save=True)
This code changes the data like:
MAPLE
H QUUX
CORGE DATA 3
E
EOF
getHeaders()
def getHeaders(
*headers: str
) -> list
| Property | Required | Value |
|---|---|---|
headers |
Target headers |
Get the list of the headers in the header block specified with the parameter.
Sample data: SampleData.mpl
MAPLE
H FOO
BAR DATA 1
H BAZ
QUX DATA 2
E
E
H QUUX
CORGE DATA 3
E
EOF
E.g.:
from maplex import MapleTree
mapleTree = MapleTree("SampleData.mpl")
headerList = mapleTree.getHeaders()
print(headerList)
# Outputs "['FOO', 'QUUX']"
saveNotes()
v2.2.0 or newer
def saveNotes(
noteValues: list[str],
*headers: str,
**kwargs
) -> None
| Property | Required | Value |
|---|---|---|
noteValues |
* | Data to save |
headers |
* | Target headers |
kwargs |
Keyword arguments |
The function saves string list as a special notes block value. Set save=True to save the changes (Default: save=False)
E.g.:
from maplex import MapleTree
mapleTree = MapleTree("SampleData.mpl", createBasaFile=True)
stringList = ["Hello", "there!"]
mapleTree.saveNotes(stringList, "FOO", "BAR", save=True)
This code creates a new file contains the following contents:
MAPLE
H FOO
H *NOTES BAR
NTE Hello
NTE there!
E
E
EOF
saveNote()
v2.2.0 or newer
def saveNote(
noteValues: str,
*headers: str,
**kwargs
) -> None
| Property | Required | Value |
|---|---|---|
noteValues |
* | Data to save |
headers |
* | Target headers |
kwargs |
Keyword arguments |
The function saves multi-lined string as a special notes block value. Set save=True to save the changes (Default: save=False)
E.g.:
from maplex import MapleTree
mapleTree = MapleTree("SampleData.mpl", createBasaFile=True)
dataString = "This is a\nmulti-lined data."
mapleTree.saveNotes(dataString, "FOO", "BAR", save=True)
This code creates a new file contains the following contents:
MAPLE
H FOO
H *NOTES BAR
NTE This is a
NTE multi-lined data.
E
E
EOF
readNotes()
v2.2.0 or newer
def readNotes(
*headers: str
) -> list[str]
| Property | Required | Value |
|---|---|---|
headers |
* | Target headers |
Read note block value which specified by the headers and return as a string list.
Sample data: SampleData.mpl
MAPLE
H FOO
H *NOTES BAR
NTE This is a
NTE multi-lined data.
E
E
EOF
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl")
stringList = mapleFile.readNotes("FOO", "BAR")
print(stringList)
# Outputs "['This is a', 'multi-lined data.']"
readNote()
v2.2.0 or newer
def readNote(
*headers: str
) -> str
| Property | Required | Value |
|---|---|---|
headers |
* | Target headers |
Read note block value which specified by the headers and return as a string.
Sample data: SampleData.mpl
MAPLE
H FOO
H *NOTES BAR
NTE This is a
NTE multi-lined data.
E
E
EOF
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl")
dataString = mapleFile.readNote("FOO", "BAR")
print(dataString)
# Outputs "This is a
# multi-lined data"
deleteNotes()
v2.2.0 or newer
def deleteNotes(
*headers: str
) -> bool
| Property | Required | Value |
|---|---|---|
headers |
* | Target headers |
kwargs |
Keyword args |
Delete note block which specified by the headers and return True if it success. Set save=True to save the changes (Default: save=False)
Sample data: SampleData.mpl
MAPLE
H FOO
H *NOTES BAR
NTE This is a
NTE multi-lined data.
E
E
EOF
E.g.:
from maplex import MapleTree
mapleFile = MapleTree("SampleData.mpl")
stringList = mapleFile.deleteNotes("FOO", "BAR", save=True)
This code changes the file data like:
MAPLE
H FOO
E
EOF
changeEncryptionKey()
v2.2.0 or newer
def changeEncryptionKey(
newKey: bytes,
save: bool = False
) -> None
| Property | Required | Value |
|---|---|---|
newKey |
* | New encryption key |
save |
Save to file flag |
Changing file encryption key. If save=True, encrypt the buffer data with new key and save to the file.
:warning: The key must be 32 url-safe base64-encoded bytes
Logger Class
Logger is a logging object for Python applications. It outputs application logs to log files and to standard output.
Logger Initialization
def __init__(
func: str = "",
workingDirectory: str | None = None,
cmdLogLevel: str | None = None,
fileLogLevel: str | None = None,
maxLogSize: float | None = None
) -> None:
| Property | Required | Value |
|---|---|---|
func |
Primary function name | |
workingDirectory |
Log file output directory | |
cmdLogLevel |
Terminal output log level | |
fileLogLevel |
Log file output log level | |
maxLogSize |
Log file max size (MB) |
The parameter overwrites the settings configured in config.mpl.
Usage
from maplex import Logger
logger = Logger("FunctionName")
logger.Info("Hello there!")
This outputs:
[INFO ][FunctionName] <module>(4) Hello there!
File output will be: log_yyyyMMdd.log
(PsNo) yyyy-MM-dd HH:mm:ss.fff [INFO ][FunctionName] <module>(4) Hello there!
Log Level
TRACEDEBUGINFOWARNERRORFATAL
ShowError function
This outputs the error logs and stuck trace.
Function:
def ShowError(
ex: Exception,
message: str | None = None,
fatal: bool = False
)
| Property | Required | Value |
|---|---|---|
ex |
* | Exception |
message |
Custom error message | |
fatal |
Show error as FATAL |
- If
fatal=True, it outputs log as aFATALlog level.
Settings
- You can configure log settings with
config.mpl. - If
config.mpldoes not exist, the instance auto-generates the file. - Instance uses the parameter values to auto-generate configuration file, or using default value if it was not specified.
Auto-generated config.mpl (parameters not specified):
MAPLE
H *LOG_SETTINGS
CMD INFO
FLE INFO
# TRACE, DEBUG, INFO, WARN,
# ERROR, FATAL, NONE
MAX 3
OUT logs
E
EOF
| TAG | Value |
|---|---|
CMD |
Console log level |
FLE |
File log level |
MAX |
Log file max size (MB) |
OUT |
Log file output path |
- To disable the log output, set log level to
NONE. - You can use a
floatnumber for the file max size (E.g.2.5for2.5MB)
Exceptions
class MapleException(Exception)
This is a basic exception class for MapleTree.
class MapleFileNotFoundException(MapleException)
This occurs when the file which specified at the instance initialization was not found.
class KeyEmptyException(MapleException)
This occurs when encrypt=True at the instance initialization, but the key for encryption is missing (None or empty).
class MapleFileLockedException(MapleException)
This occurs when the instance tries to open the file, but the other instance has already locked the file.
class MapleDataNotFoundException(MapleException)
This occurs when the data is not found in the file.
MapleEncryptionNotEnabledException(MapleException)
This occurs when try to encrypt maple data, but the encryption flag is False.
class MapleHeaderNotFoundException(MapleDataNotFoundException)
This occurs when the header (specified by the user) is not found in the data.
class MapleTagNotFoundException(MapleDataNotFoundException)
This occurs when the tag (specified by the user) is not found in the data.
class NotAMapleFileException(MapleDataNotFoundException)
This occurs when the file is not a Maple file.
- The file without a "MAPLE" line.
class InvalidMapleFileFormatException(NotAMapleFileException)
This occurs when the file format is an invalid Maple format.
- The file has a "MAPLE" line, but the format is wrong or broken.
class MapleFileEmptyException(NotAMapleFileException)
This occurs when the file is empty (No data)
class MapleSyntaxException(MapleException)
This occurs when the syntax of the MapleTree function (mostly its parameter) is invalid.
class MapleTypeException(MapleSyntaxException)
This occurs when the user hands the unknown keyword arguments as the **kwargs to the MapleTree function.
Console Colors
Standard colors
| Key | Value | Color |
|---|---|---|
Black |
\033[30m | Black |
Red |
\033[31m | Red |
Green |
\033[32m | Green |
Yellow |
\033[33m | Yellow |
Blue |
\033[34m | Blue |
Magenta |
\033[35m | Magenta |
LightBlue |
\033[36m | LightBlue |
White |
\033[37m | White |
Bright colors
| Key | Value | Color |
|---|---|---|
bBlack |
\033[90m | Black |
bRed |
\033[91m | Red |
bGreen |
\033[92m | Green |
bYellow |
\033[93m | Yellow |
bBlue |
\033[94m | Blue |
bMagenta |
\033[95m | Magenta |
bLightBlue |
\033[96m | LightBlue |
bWhite |
\033[97m | White |
Background colors
| Key | Value | Color |
|---|---|---|
bgBlack |
\033[40m | Black |
bgRed |
\033[41m | Red |
bgGreen |
\033[42m | Green |
bgYellow |
\033[43m | Yellow |
bgBlue |
\033[44m | Blue |
bgMagenta |
\033[45m | Magenta |
bgLightBlue |
\033[46m | LightBlue |
bgWhite |
\033[47m | White |
Other formats
| Key | Value | Description |
|---|---|---|
Bold |
\033[1m | Bold text |
Underline |
\033[4m | Underlined text |
Reversed |
\033[7m | Reversed colors |
Reset |
\033[0m | Reset formatting |
Install MapleX
From PyPI
[python[3] -m] pip install MapleX [--break-system-packages]
Manual Installation
- Download
./dist/maplex-<version>-py3-none-any.whl - Run
[python[3] -m] pip install /path/to/downloaded/maplex-<version>-py3-none-any.whl [--break-system-packages]
Build the Package by Yourself
Run python[3] -m build
or
Run python[3] setup.py sdist bdist_wheel
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file maplex-2.2.0b1.tar.gz.
File metadata
- Download URL: maplex-2.2.0b1.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7645a479ff7a3b0e445aa15f5ad5150485c89359df08588d33dfc3816cfdda8
|
|
| MD5 |
f13dccf9804ca5224fffacfa2258e515
|
|
| BLAKE2b-256 |
b38407c3b35b0d9f1972f17f07efd7478335d95753c98659d432f2fb1ef2d13e
|
Provenance
The following attestation bundles were made for maplex-2.2.0b1.tar.gz:
Publisher:
python-publish.yml on Ryuji-Hazama/MapleTree
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
maplex-2.2.0b1.tar.gz -
Subject digest:
c7645a479ff7a3b0e445aa15f5ad5150485c89359df08588d33dfc3816cfdda8 - Sigstore transparency entry: 813576825
- Sigstore integration time:
-
Permalink:
Ryuji-Hazama/MapleTree@3d89de05bd8a15e358ed34e4b2450eb1337048dd -
Branch / Tag:
refs/tags/v2.2.0b1 - Owner: https://github.com/Ryuji-Hazama
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@3d89de05bd8a15e358ed34e4b2450eb1337048dd -
Trigger Event:
release
-
Statement type:
File details
Details for the file maplex-2.2.0b1-py3-none-any.whl.
File metadata
- Download URL: maplex-2.2.0b1-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fa2718ee6f18053f65f3e9b226c43f6924310b25351719c76517cfd4ec8e7e8
|
|
| MD5 |
de4c4b68352c6665ec8c6c9ebbb23c00
|
|
| BLAKE2b-256 |
959fa53e41fcd846d1f7a154a5645b3cce51446fa7bfc2a0355293ef1f5fe333
|
Provenance
The following attestation bundles were made for maplex-2.2.0b1-py3-none-any.whl:
Publisher:
python-publish.yml on Ryuji-Hazama/MapleTree
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
maplex-2.2.0b1-py3-none-any.whl -
Subject digest:
0fa2718ee6f18053f65f3e9b226c43f6924310b25351719c76517cfd4ec8e7e8 - Sigstore transparency entry: 813576826
- Sigstore integration time:
-
Permalink:
Ryuji-Hazama/MapleTree@3d89de05bd8a15e358ed34e4b2450eb1337048dd -
Branch / Tag:
refs/tags/v2.2.0b1 - Owner: https://github.com/Ryuji-Hazama
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@3d89de05bd8a15e358ed34e4b2450eb1337048dd -
Trigger Event:
release
-
Statement type: