VIStk 0.3.12.14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
VIStk/Form.zip ADDED
Binary file
VIStk/Objects/_Root.py ADDED
@@ -0,0 +1,9 @@
1
+ from tkinter import *
2
+ from VIStk.Objects._WindowGeometry import WindowGeometry
3
+ from VIStk.Objects._Window import Window
4
+
5
+ class Root(Tk, Window):
6
+ """A wrapper for the Tk class with VIS attributes"""
7
+ def __init__(self,*args,**kwargs):
8
+ super().__init__(*args,**kwargs)
9
+ self.WindowGeometry = WindowGeometry(self)
@@ -0,0 +1,18 @@
1
+ from tkinter import *
2
+ from VIStk.Objects._WindowGeometry import WindowGeometry
3
+ from VIStk.Objects._Window import Window
4
+
5
+ class SubRoot(Toplevel, Window):
6
+ """A wrapper for the Toplevel class with VIS attributes"""
7
+ def __init__(self,*args,**kwargs):
8
+ super().__init__(*args,**kwargs)
9
+ self.WindowGeometry = WindowGeometry(self)
10
+
11
+ def modalize(self):
12
+ """Makes the SubWindow modal"""
13
+ self.focus_force()
14
+
15
+ self.transient(self.master)
16
+ self.grab_set()
17
+
18
+ self.master.wait_window(self)
@@ -0,0 +1,24 @@
1
+ from tkinter import *
2
+
3
+ class Window:
4
+ """A VIS Window object"""
5
+ def __init__(self):
6
+ """Initializes the VIS Window"""
7
+
8
+ def fullscreen(self,absolute:bool=False):
9
+ if absolute is False:
10
+ try: #On Linux
11
+ self.wm_attributes("-zoomed", True)
12
+ except TclError: #On Windows
13
+ self.state('zoomed')
14
+ else:
15
+ self.attributes("-fullscreen", True)
16
+
17
+ def unfullscreen(self,absolute:bool=False):
18
+ if absolute is False:
19
+ try: #On Linux
20
+ self.wm_attributes("-zoomed", False)
21
+ except TclError: #On Windows
22
+ self.state('normal')
23
+ else:
24
+ self.attributes("-fullscreen", False)
@@ -0,0 +1,133 @@
1
+ from tkinter import *
2
+ from typing import Literal
3
+
4
+ query = Tk()
5
+ try: #On Linux
6
+ query.wm_attributes("-zoomed", True)
7
+ except TclError: #On Windows
8
+ query.state('zoomed')
9
+ query.update()
10
+ global hs, ws
11
+ ws = query.winfo_width()-2#Unclear about this offset
12
+ hs = query.winfo_height()-9#Might be operating system specific
13
+ query.destroy()
14
+ print(f"Screen has usable size of {ws}x{hs}")
15
+
16
+ class WindowGeometry():
17
+ """Handles geometry relations and sizing/resizing for windows"""
18
+ def __init__(self,window:Tk|Toplevel):
19
+ """Creates a window geometry object and automatically extracts the size and location
20
+
21
+ Args:
22
+ window (Tk|Toplevel): The window to access geometry of
23
+ """
24
+ self.window:Tk|Toplevel = window
25
+ self.getGeometry()
26
+ window.WindowGeometry = self
27
+
28
+ def getGeometry(self, respect_size:bool=False):
29
+ """Sets the internal geometry of object to match the window"""
30
+ geo_str = self.window.geometry()
31
+ geo_list = geo_str.split("x")
32
+ ng_list = [int(geo_list[0])]
33
+ for i in geo_list[1].split("+"):
34
+ ng_list.append(int(i))
35
+
36
+ if respect_size:
37
+ self.geometry = [self.window.winfo_width(), self.window.winfo_height(), ng_list[2], ng_list[3]]
38
+ else:
39
+ self.geometry = ng_list
40
+
41
+ def stripGeometry(self,objects:tuple[Literal["w","h","x","y"]]|Literal["all"]):
42
+ """Returns integer values of the requested items"""
43
+ geo_str = self.window.geometry()
44
+ geo_list = geo_str.split("x")
45
+ ng_list = [int(geo_list[0])]
46
+ for i in geo_list[1].split("+"):
47
+ ng_list.append(int(i))
48
+
49
+ geo_list = []
50
+ if objects == "all":
51
+ geo_list = ng_list
52
+ else:
53
+ if "w" in objects: geo_list.append(ng_list[0])
54
+ if "h" in objects: geo_list.append(ng_list[1])
55
+ if "x" in objects: geo_list.append(ng_list[2])
56
+ if "y" in objects: geo_list.append(ng_list[3])
57
+
58
+ return geo_list
59
+
60
+
61
+ def setGeometry(self,width:int=None,height:int=None,x:int=None,y:int=None,align:Literal["center","n","ne","e","se","s","sw","w","nw"]=None,size_style:Literal["pixels","screen_relative","window_relative"]=None,window_ref:Tk|Toplevel=None):
62
+ """Sets the geometry of the window"""
63
+ global hs, ws
64
+ ox, oy = 0, 0
65
+
66
+ if width is None: width = self.geometry[0]
67
+ if height is None: height = self.geometry[1]
68
+
69
+ #Check if aligning or using coordinates
70
+ if align is None:
71
+ if x is None: x = self.geometry[2]
72
+ if y is None: y = self.geometry[3]
73
+ else:
74
+ x = None
75
+ y = None
76
+
77
+ #No adjustment needs to be made if pixels are given
78
+
79
+ if size_style == "window_relative":
80
+ if not window_ref is None:
81
+ _ws = window_ref.winfo_width()
82
+ _hs = window_ref.winfo_height()
83
+
84
+ if not _ws is None: ws = _ws
85
+ if not _hs is None: hs = _hs
86
+
87
+ geo_ref = WindowGeometry(window_ref).stripGeometry(("x","y"))
88
+
89
+ ox = geo_ref[0]
90
+ oy = geo_ref[1]
91
+
92
+ #Will always hand over relative sizing to screen relative
93
+ size_style = "screen_relative"
94
+
95
+ if size_style == "screen_relative":
96
+ if not width == self.geometry[0]:
97
+ width = ws*width/100
98
+
99
+ if not height == self.geometry[1]:
100
+ height = hs*height/100
101
+
102
+ if not align is None:
103
+ match align:
104
+ case "center":
105
+ x = ws/2 - width/2 + ox
106
+ y = hs/2 - height/2 + oy
107
+ case "n":
108
+ x = ws/2 - width/2 + ox
109
+ y = 0 + oy
110
+ case "ne":
111
+ x = ws - width + ox
112
+ y = 0 + oy
113
+ case "e":
114
+ x = ws - width + ox
115
+ y = hs/2 - height/2 + oy
116
+ case "se":
117
+ x = ws - width + ox
118
+ y = hs - height + oy
119
+ case "s":
120
+ x = ws/2 - width/2 + ox
121
+ y = hs - height + oy
122
+ case "sw":
123
+ x = 0 + ox
124
+ y = hs - height + oy
125
+ case "w":
126
+ x = 0 + ox
127
+ y = hs/2 - height/2 + oy
128
+ case "nw":
129
+ x = 0 + ox
130
+ y = 0 + oy
131
+
132
+ self.geometry = [int(width), int(height), int(x-7), int(y)]
133
+ self.window.geometry('%dx%d+%d+%d' % tuple(self.geometry))
@@ -0,0 +1,6 @@
1
+ from VIStk.Objects._WindowGeometry import *
2
+ from VIStk.Objects._Root import *
3
+ from VIStk.Objects._SubRoot import *
4
+ from VIStk.Objects._Window import *
5
+
6
+ __all__ = ["WindowGeometry","Root","SubRoot","Window"]
@@ -0,0 +1,139 @@
1
+ import os
2
+ import json
3
+ import zipfile
4
+ import shutil
5
+ import subprocess
6
+
7
+ #Copied from source
8
+ #https://stackoverflow.com/a/75246706
9
+ def unzip_without_overwrite(src_path, dst_dir):
10
+ with zipfile.ZipFile(src_path, "r") as zf:
11
+ for member in zf.infolist():
12
+ file_path = os.path.join(dst_dir, member.filename)
13
+ if not os.path.exists(file_path):
14
+ zf.extract(member, dst_dir)
15
+
16
+ def getPath():
17
+ """Searches for .VIS folder and returns from path.cfg
18
+ """
19
+ sto = 0
20
+ while True:
21
+ try:
22
+ step=""
23
+ for i in range(0,sto,1): #iterate on sto to step backwards and search for project info
24
+ step = "../" + step
25
+ if os.path.exists(step+".VIS/"):
26
+ return open(step+".VIS/path.cfg","r").read().replace("\\","/") #return stored path
27
+ else:
28
+ if os.path.exists(step):
29
+ sto += 1
30
+ else:
31
+ return None #return none if cant escape more
32
+ except:
33
+ return None #if failed return none
34
+
35
+ def validName(name:str):
36
+ """Checks if provided path is a valid filename
37
+ """
38
+ if " " in name:
39
+ print("Cannot have spaces in file name.")
40
+ return False
41
+ if "/" in name or "\\" in name:
42
+ print("Cannot have filepath deliminator in file name.")
43
+ return False
44
+ if "<" in name or ">" in name or ":" in name or '"' in name or "|" in name or "?" in name or "*" in name:
45
+ print('Invlaid ASCII characters for windows file creation, please remove all <>:"|?* from file name.')
46
+ return False
47
+ if name.split(".")[0] in ["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"]:
48
+ print(f"Filename {name} reserved by OS.")
49
+ return False
50
+ if "" == name:
51
+ print("Must provide a name for file.")
52
+ return False
53
+ else:
54
+ return True
55
+
56
+
57
+ class VINFO():
58
+ """Overarching control structure within the /.VIS/ folder
59
+ """
60
+ def __init__(self):
61
+ if getPath() == None:
62
+ wd = os.getcwd()
63
+ os.mkdir(wd+"\\.VIS")
64
+ open(wd+"/.VIS/path.cfg","w").write(wd) if os.path.exists(wd+"/.VIS/path.cfg") else open(wd+"/.VIS/path.cfg", 'a').write(wd)
65
+ print(f"Stored project path in path.cfg as {wd} in {wd}/.VIS/path.cfg")
66
+
67
+ unzip_without_overwrite("Form.zip",wd)
68
+ print(f"Copied structure to {wd}")
69
+
70
+ shutil.copytree("./Templates",wd+"/.VIS/Templates",dirs_exist_ok=True)
71
+ print(f"Loaded default templates into {wd}/.VIS/Templates/")
72
+
73
+
74
+ #DO NOT MESS WITH THE TEMPLATE HEADERS
75
+
76
+ title = input("Enter a name for the VIS project: ")
77
+ self.title = title
78
+ info = {}
79
+ info[self.title] = {}
80
+ info[self.title]["Screens"]={}
81
+ info[self.title]["defaults"]={}
82
+ info[self.title]["defaults"]["icon"]="VIS"#default icon
83
+ self.d_icon = "VIS"
84
+ self[self.title]["metadata"]={}
85
+ comp = input("What company is this for(or none)? ")
86
+ if not comp in ["none","None"]:
87
+ info[self.title]["metadata"]["company"] = comp
88
+ self.company = comp
89
+ else:
90
+ info[self.title]["metadata"]["company"] = None
91
+ self.company = None
92
+
93
+ version = input("What is the initial version for the project (0.0.1 default): ")
94
+ vers = version.split(".")
95
+ if len(vers)==3:
96
+ if vers[0].isnumeric() and vers[1].isnumeric() and vers[2].isnumeric():
97
+ self.version = version
98
+ else:
99
+ self.version = "0.0.1"
100
+ else:
101
+ self.version = "0.0.1"
102
+ info[self.title]["metadata"]["version"] = self.version
103
+
104
+ with open(wd+"/.VIS/project.json","w") as f:
105
+ f.write("{}")
106
+ json.dump(info,f,indent=4)
107
+ print(f"Setup project.json for project {self.title} in {wd}/.VIS/")
108
+
109
+
110
+ #Need to get current python location where VIS is installed
111
+ self.p_vis = subprocess.check_output('python -c "import os, sys; print(os.path.dirname(sys.executable))"').decode().strip("\r\n")+"\\Lib\\site-packages\\VIS\\"
112
+
113
+
114
+ self.p_project = getPath()
115
+ self.p_vinfo = self.p_project + "/.VIS"
116
+ self.p_sinfo = self.p_vinfo + "/project.json"
117
+ with open(self.p_sinfo,"r") as f:
118
+ info = json.load(f)
119
+ self.title = list(info.keys())[0]
120
+ self.version = info[self.title]["metadata"]["version"]
121
+ self.company = info[self.title]["metadata"]["company"]
122
+
123
+ self.screenlist = []
124
+ self.p_screens = self.p_project +"/Screens"
125
+ self.p_modules = self.p_project +"/modules"
126
+ self.p_templates = self.p_vinfo + "/Templates"
127
+ self.p_icons = self.p_project + "/Icons"
128
+ self.p_images = self.p_project + "/Images"
129
+
130
+ def setVersion(self,version:str):
131
+ """Sets a new project version
132
+ """
133
+ with open(self.p_sinfo,"r") as f:
134
+ info = json.load(f)
135
+
136
+ info[self.title]["metadata"]["version"] = version
137
+
138
+ with open(self.p_sinfo,"w") as f:
139
+ json.dump(info,f,indent=4)
@@ -0,0 +1,6 @@
1
+ from VIStk.Structures.project import *
2
+ from VIStk.Structures.release import *
3
+ from VIStk.Structures.screen import *
4
+ from VIStk.Structures.VINFO import *
5
+
6
+ __all__ = ["Project", "Release", "Screen", "VINFO"]
@@ -0,0 +1,92 @@
1
+ import json
2
+ from VIStk.Structures.VINFO import *
3
+ from VIStk.Structures.screen import *
4
+
5
+ class Project(VINFO):
6
+ """VIS Project Object
7
+ """
8
+ def __init__(self):
9
+ """Initializes or load a VIS project
10
+ """
11
+ super().__init__()
12
+ with open(self.p_sinfo,"r") as f:
13
+ info = json.load(f)
14
+ self.name = list(info.keys())[0]
15
+
16
+ for screen in list(info[self.name]["Screens"].keys()):
17
+ scr = Screen(screen,
18
+ info[self.name]["Screens"][screen]["script"],
19
+ info[self.name]["Screens"][screen]["release"],
20
+ info[self.name]["Screens"][screen].get("icon"),
21
+ exists=True)
22
+ self.screenlist.append(scr)
23
+ self.d_icon = info[self.name]["defaults"]["icon"]
24
+
25
+ def newScreen(self,screen:str) -> int:
26
+ """Creates a new screen with some prompting
27
+
28
+ Returns:
29
+ 0 Failed
30
+ 1 Success
31
+ """
32
+ #Check for valid filename
33
+ if not validName(screen):
34
+ return 0
35
+
36
+ with open(self.p_sinfo,"r") as f:
37
+ info = json.load(f) #Load info
38
+
39
+ name = self.title
40
+ if info[name]["Screens"].get(screen) == None: #If Screen does not exist in VINFO
41
+ while True: #ensures a valid name is used for script
42
+ match input(f"Should python script use name {screen}.py? "):
43
+ case "Yes" | "yes" | "Y" | "y":
44
+ script = screen + ".py"
45
+ break
46
+ case _:
47
+ script = input("Enter the name for the script file: ").strip(".py")+".py"
48
+ if validName(script):
49
+ break
50
+
51
+ match input("Should this screen have its own .exe?: "):
52
+ case "Yes" | "yes" | "Y" | "y":
53
+ release = True
54
+ case _:
55
+ release = False
56
+ ictf =input("What is the icon for this screen (or none)?: ")
57
+ icon = ictf.strip(".ico") if ".ICO" in ictf.upper() else None
58
+ desc = input("Write a description for this screen: ")
59
+ self.screenlist.append(Screen(screen,script,release,icon,False,desc))
60
+
61
+ return 1
62
+ else:
63
+ print(f"Information for {screen} already in project.")
64
+ return 1
65
+
66
+ def hasScreen(self,screen:str) -> bool:
67
+ """Checks if the project has the correct screen
68
+ """
69
+ for i in self.screenlist:
70
+ if i.name == screen:
71
+ return True
72
+ return False
73
+
74
+ def getScreen(self,screen:str) -> Screen:
75
+ """Returns a screen object by its name
76
+ """
77
+ for i in self.screenlist:
78
+ if i.name == screen:
79
+ return i
80
+ return None
81
+
82
+ def verScreen(self,screen:str) -> Screen:
83
+ """Verifies a screen exists and returns it
84
+
85
+ Returns:
86
+ screen (Screen): Verified screen
87
+ """
88
+ if not self.hasScreen(screen):
89
+ self.newScreen(screen)
90
+ scr = self.getScreen(screen)
91
+ return scr
92
+
@@ -0,0 +1,165 @@
1
+ from VIStk.Structures.project import *
2
+ from VIStk.Structures.VINFO import *
3
+ from VIStk.Structures.screen import *
4
+ import subprocess
5
+ import shutil
6
+ from os.path import exists
7
+ import time
8
+ import datetime
9
+
10
+ info = {}
11
+
12
+ class Release():
13
+ """A VIS Release object"""
14
+ def __init__(self, project :Project, version:str="",type:str="",note:str=""):
15
+ """Creates a Release object to release or examine a releaes of a project"""
16
+ self.project = project
17
+ self.version = version
18
+ self.type = type
19
+ self.note = note
20
+
21
+ def build(self):
22
+ """Build project spec file for release
23
+ """
24
+
25
+ print(f"Creating project.spec for {self.project.name}")
26
+
27
+ with open(self.project.p_vinfo+"/Templates/spec.txt","r") as f:
28
+ spec = f.read()
29
+ with open(self.project.p_vinfo+"/Templates/collect.txt","r") as f:
30
+ collect = f.read()
31
+
32
+ spec_list = []
33
+ name_list = []
34
+ os.mkdir(self.project.p_vinfo+"/Build")
35
+ for i in self.project.screenlist:
36
+ if i.release:
37
+ name_list.append(i.name)
38
+ if not i.icon == None:
39
+ icon = i.icon
40
+ else:
41
+ icon = self.project.d_icon
42
+ spec_list.append(spec.replace("$name$",i.name))
43
+ spec_list[len(spec_list)-1] = spec_list[len(spec_list)-1].replace("$icon$",icon)
44
+ spec_list[len(spec_list)-1] = spec_list[len(spec_list)-1].replace("$file$",i.script)
45
+
46
+ #build metadata
47
+ with open(self.project.p_templates+"/version.txt","r") as f:
48
+ meta = f.read()
49
+
50
+ #Update Overall Project Version
51
+ vers = self.project.version.split(".")
52
+ major = vers[0]
53
+ minor = vers[1]
54
+ patch = vers[2]
55
+ meta = meta.replace("$M$",major)
56
+ meta = meta.replace("$m$",minor)
57
+ meta = meta.replace("$p$",patch)
58
+
59
+ #Update Screen Version
60
+ vers = i.s_version.split(".")
61
+ major = vers[0]
62
+ minor = vers[1]
63
+ patch = vers[2]
64
+ meta = meta.replace("$sM$",major)
65
+ meta = meta.replace("$sm$",minor)
66
+ meta = meta.replace("$sp$",patch)
67
+
68
+ if self.project.company != None:
69
+ meta = meta.replace("$company$",self.project.company)
70
+ meta = meta.replace("$year$",str(datetime.datetime.now().year))
71
+ else:
72
+ meta = meta.replace(" VALUE \"CompanyName\", VER_COMPANYNAME_STR\n","")
73
+ meta = meta.replace(" VALUE \"LegalCopyright\", VER_LEGALCOPYRIGHT_STR\n","")
74
+ meta = meta.replace("#define VER_LEGAL_COPYRIGHT_STR \"Copyright © $year$ $company$\\0\"\n\n","")
75
+ meta = meta.replace("$name$",i.name)
76
+ meta = meta.replace("$desc$",i.desc)
77
+
78
+ with open(self.project.p_vinfo+f"/Build/{i.name}.txt","w") as f:
79
+ f.write(meta)
80
+ spec_list[len(spec_list)-1] = spec_list[len(spec_list)-1].replace("$meta$",self.project.p_vinfo+f"/Build/{i.name}.txt")
81
+ spec_list.append("\n\n")
82
+
83
+ insert = ""
84
+ for i in name_list:
85
+ insert=insert+"\n\t"+i+"_exe,\n\t"+i+"_a.binaries,\n\t"+i+"_a.zipfiles,\n\t"+i+"_a.datas,"
86
+ collect = collect.replace("$insert$",insert)
87
+ collect = collect.replace("$version$",self.project.name+"-"+self.version) if not self.version == "" else collect.replace("$version$",self.project.name)
88
+
89
+ header = "# -*- mode: python ; coding: utf-8 -*-\n\n\n"
90
+
91
+ with open(self.project.p_vinfo+"/project.spec","w") as f:
92
+ f.write(header)
93
+ with open(self.project.p_vinfo+"/project.spec","a") as f:
94
+ f.writelines(spec_list)
95
+ f.write(collect)
96
+
97
+ print(f"Finished creating project.spec for {self.project.title} {self.version if not self.version =="" else "current"}")#advanced version will improve this
98
+
99
+ def clean(self):
100
+ """Cleans up build environment to save space
101
+ """
102
+ print("Cleaning up build environment")
103
+ shutil.rmtree(self.project.p_vinfo+"/Build")
104
+ print("Appending Screen Data To Environment")
105
+ if self.version == " ":
106
+ if exists(f"{self.project.p_project}/dist/{self.project.title}/Icons/"): shutil.rmtree(f"{self.project.p_project}/dist/{self.project.title}/Icons/")
107
+ if exists(f"{self.project.p_project}/dist/{self.project.title}/Images/"): shutil.rmtree(f"{self.project.p_project}/dist/{self.project.title}/Images/")
108
+ shutil.copytree(self.project.p_project+"/Icons/",f"{self.project.p_project}/dist/{self.project.title}/Icons/",dirs_exist_ok=True)
109
+ shutil.copytree(self.project.p_project+"/Images/",f"{self.project.p_project}/dist/{self.project.title}/Images/",dirs_exist_ok=True)
110
+ else:
111
+ if exists(f"{self.project.p_project}/dist/{self.project.title}/Icons/"): shutil.rmtree(f"{self.project.p_project}/dist/{self.project.name}/Icons/")
112
+ if exists(f"{self.project.p_project}/dist/{self.project.title}/Images/"): shutil.rmtree(f"{self.project.p_project}/dist/{self.project.name}/Images/")
113
+ shutil.copytree(self.project.p_project+"/Icons/",f"{self.project.p_project}/dist/{self.project.title}-{self.version.strip(" ")}/Icons/",dirs_exist_ok=True)
114
+ shutil.copytree(self.project.p_project+"/Images/",f"{self.project.p_project}/dist/{self.project.title}-{self.version.strip(" ")}/Images/",dirs_exist_ok=True)
115
+ print(f"\n\nReleased new{self.version}build of {self.project.title}!")
116
+
117
+ def newVersion(self):
118
+ """Updates the project version, PERMANENT, cannot be undone
119
+ """
120
+ old = str(self.project.version)
121
+ vers = self.project.version.split(".")
122
+ if self.version == "Major":
123
+ vers[0] = str(int(vers[0])+1)
124
+ vers[1] = str(0)
125
+ vers[2] = str(0)
126
+ if self.version == "Minor":
127
+ vers[1] = str(int(vers[1])+1)
128
+ vers[2] = str(0)
129
+ if self.version == "Patch":
130
+ vers[2] = str(int(vers[2])+1)
131
+
132
+ self.project.setVersion(f"{vers[0]}.{vers[1]}.{vers[2]}")
133
+ self.project = VINFO()
134
+ print(f"Updated Version {old}=>{self.project.version}")
135
+
136
+ def makeRelease(self):
137
+ """Releases a version of your project
138
+ """
139
+ match self.version:
140
+ case "a":
141
+ self.build("alpha")
142
+ subprocess.call(f"pyinstaller {self.project.p_vinfo}/project.spec --noconfirm --distpath {self.project.p_project}/dist/ --log-level FATAL")
143
+ self.clean(" alpha ")
144
+ case "b":
145
+ self.build("beta")
146
+ subprocess.call(f"pyinstaller {self.project.p_vinfo}/project.spec --noconfirm --distpath {self.project.p_project}/dist/ --log-level FATAL")
147
+ self.clean(" beta ")
148
+ case "c":
149
+ self.newVersion(type)
150
+ self.build()
151
+ subprocess.call(f"pyinstaller {self.project.p_vinfo}/project.spec --noconfirm --distpath {self.project.p_project}/dist/ --log-level FATAL")
152
+ self.clean()
153
+ case "sync":
154
+ self.build("alpha")
155
+ subprocess.call(f"pyinstaller {self.project.p_vinfo}/project.spec --noconfirm --distpath {self.project.p_project}/dist/ --log-level FATAL")
156
+ self.clean(" alpha ")
157
+ self.build("beta")
158
+ subprocess.call(f"pyinstaller {self.project.p_vinfo}/project.spec --noconfirm --distpath {self.project.p_project}/dist/ --log-level FATAL")
159
+ self.clean(" beta ")
160
+ self.build()
161
+ subprocess.call(f"pyinstaller {self.project.p_vinfo}/project.spec --noconfirm --distpath {self.project.p_project}/dist/ --log-level FATAL")
162
+ self.clean()
163
+ print("\t- alpha\n\t- beta\n\t- current")
164
+ case _:
165
+ print(f"Could not release Project Version {self.version}")