Module libbottles.bottle
Expand source code
import json
from glob import glob
from random import seed, randint
from libbottles.utils.checks import check_special_chars
from libbottles.components.runner import Runner
from libbottles import globals
from libwine.wine import Wine
seed(1)
class Bottle:
"""
Create a new object of type Bottle with all the methods for its management.
Parameters
----------
path : str
the bottle full path
"""
config = {}
_config_struct = {
"Name": "",
"Runner": "",
"DXVK": "",
"Path": "",
"Environment": 2,
"Creation_Date": "",
"Update_Date": "",
"Versioning": False,
"State": 0,
"Verbose": 0,
"Parameters": {
"dxvk": False,
"dxvk_hud": False,
"sync": "wine",
"aco_compiler": False,
"discrete_gpu": False,
"virtual_desktop": False,
"virtual_desktop_res": "1280x720",
"pulseaudio_latency": False,
"environment_variables": "",
},
"Installed_Dependencies": [],
"DLL_Overrides": {},
"Programs": {}
}
_environments = [
{
"Name": "Software",
"Parameters": {
"dxvk": True
}
},
{
"Name": "Gaming",
"Parameters": {
"dxvk": True,
"sync": "esync",
"discrete_gpu": True,
"pulseaudio_latency": True
}
},
{
"Name": "Custom",
"Parameters": {}
}
]
_supported_sync_types = {
0: "wine",
1: "esync",
2: "fsync"
}
wineprefix = object
def __init__(
self,
path: str,
create: bool = False,
env: int = 3,
name: str = None,
runner_path: str = None,
verbose: int = 0,
versioning: bool = False):
if not create:
self.__validate(path)
self.__load_config(path)
self.__set_wineprefix(runner_path)
else:
self.config = {
"Path": path,
"Name": name,
"Runner": runner_path,
"Environment": env,
"Verbose": verbose,
"Versioning": versioning
}
self.__set_wineprefix(runner_path)
self.wineprefix.update()
self.__load_config(path)
self.apply_environment(env)
'''
Bottle checks
'''
@staticmethod
def __validate(path):
"""
Check if essential paths exist in path.
Parameters
----------
path : str
the bottle full path
"""
promise = ["dosdevices", "drive_c"]
dirs = glob(f"{path}/*")
dirs = [d.replace(f"{path}/", "") for d in dirs]
for p in promise:
if p not in dirs:
raise ValueError("Given path doesn't seem a valid Bottle path.")
return True
def __load_config(self, path):
"""
Load config from path, if doesn't exists then create.
Also update config structure if outdated.
Parameters
----------
path : str
the bottle full path
"""
try:
file = open(f"{path}/bottle.json")
self.config = json.load(file)
file.close()
except FileNotFoundError:
file = open(f"{path}/bottle.json", "w")
if len(self.config) == 0:
config = self._config_struct
config["Name"] = f"Generated {randint(10000, 20000)}"
config["Path"] = path
# TODO: set runner to latest installed
json.dump(config, file, indent=4)
self.config = json.load(file)
else:
config = self.config
json.dump(config, file, indent=4)
file.close()
'''
Check for diffs. between _config_struct and the bottle one, then update.
'''
missing_keys = self._config_struct.keys() - self.config.keys()
for key in missing_keys:
self.update_config(
key=key,
value=self._config_struct[key]
)
missing_keys = (
self._config_struct["Parameters"].keys() -
self.config["Parameters"].keys()
)
for key in missing_keys:
self.update_config(
key=key,
value=self._config_struct["Parameters"][key],
scope="Parameters"
)
'''
Wineprefix instance
'''
def __set_wineprefix(self, runner_path: str = None):
if not runner_path:
runner_path = self.config["Runner"]
self.wineprefix = Wine(
winepath=runner_path,
wineprefix=self.config["Path"],
verbose=self.config["Verbose"]
)
'''
Bottle config tools
'''
def apply_environment(self, environment: int):
if not self._environments[environment]:
raise ValueError(f"{environment} is not a valid environment.")
self.update_config(
key="Environment",
value=environment
)
# TODO: work in progress
return
def apply_config(self, config: dict):
for key, value in config.items():
self.update_config(
key=key,
value=value
)
def update_config(
self,
key: str = None,
value: str = None,
scope: str = None):
"""
Update keys for a bottle config.
Parameters
----------
key : str
the key name
value : str
the value to be set
scope : str (optional)
where to look for the key if it is not the root (default is None)
"""
if scope is not None:
self.config[scope][key] = value
else:
self.config[key] = value
file = open(
f"{self.config['Path']}/bottle.json", "w")
json.dump(self.config, file, indent=4)
file.close()
'''
Bottle management
'''
def rename(self, name: str):
if not check_special_chars(text=name):
return self.update_config(
key="Name",
value=name
)
raise ValueError("The bottle name cannot contain special characters.")
def set_runner(self):
# TODO
pass
def set_versioning(self):
# TODO
pass
def set_verbose(self, level: int):
self.update_config(
key="Verbose",
value=level
)
self.wineprefix.set_verbose(level)
def set_dxvk_hud(self, status: bool):
self.update_config(
key="dxvk_hud",
value=status,
scope="Parameters"
)
def set_sync(self, sync_type: int):
if sync_type not in self._supported_sync_types:
raise ValueError(f"{sync_type} is not a valid sync type.")
self.update_config(
key="sync",
value=sync_type,
scope="Parameters"
)
def set_aco_compiler(self, status: bool):
self.update_config(
key="aco_compiler",
value=status,
scope="Parameters"
)
def set_discrete_gpu(self, status: bool):
self.update_config(
key="discrete_gpu",
value=status,
scope="Parameters"
)
def set_virtual_desktop(self, status: bool):
self.update_config(
key="virtual_desktop",
value=status,
scope="Parameters"
)
if not status:
self.wineprefix.set_virtual_desktop(False)
def set_virtual_desktop_res(self, res: str):
self.set_virtual_desktop(True)
self.update_config(
key="virtual_desktop_res",
value=res,
scope="Parameters"
)
self.wineprefix.set_virtual_desktop(
status=True,
res=res
)
def set_pulseaudio_latency(self, status: bool):
self.update_config(
key="pulseaudio_latency",
value=status,
scope="Parameters"
)
Classes
class Bottle (path: str, create: bool = False, env: int = 3, name: str = None, runner_path: str = None, verbose: int = 0, versioning: bool = False)
-
Create a new object of type Bottle with all the methods for its management.
Parameters
path
:str
- the bottle full path
Expand source code
class Bottle: """ Create a new object of type Bottle with all the methods for its management. Parameters ---------- path : str the bottle full path """ config = {} _config_struct = { "Name": "", "Runner": "", "DXVK": "", "Path": "", "Environment": 2, "Creation_Date": "", "Update_Date": "", "Versioning": False, "State": 0, "Verbose": 0, "Parameters": { "dxvk": False, "dxvk_hud": False, "sync": "wine", "aco_compiler": False, "discrete_gpu": False, "virtual_desktop": False, "virtual_desktop_res": "1280x720", "pulseaudio_latency": False, "environment_variables": "", }, "Installed_Dependencies": [], "DLL_Overrides": {}, "Programs": {} } _environments = [ { "Name": "Software", "Parameters": { "dxvk": True } }, { "Name": "Gaming", "Parameters": { "dxvk": True, "sync": "esync", "discrete_gpu": True, "pulseaudio_latency": True } }, { "Name": "Custom", "Parameters": {} } ] _supported_sync_types = { 0: "wine", 1: "esync", 2: "fsync" } wineprefix = object def __init__( self, path: str, create: bool = False, env: int = 3, name: str = None, runner_path: str = None, verbose: int = 0, versioning: bool = False): if not create: self.__validate(path) self.__load_config(path) self.__set_wineprefix(runner_path) else: self.config = { "Path": path, "Name": name, "Runner": runner_path, "Environment": env, "Verbose": verbose, "Versioning": versioning } self.__set_wineprefix(runner_path) self.wineprefix.update() self.__load_config(path) self.apply_environment(env) ''' Bottle checks ''' @staticmethod def __validate(path): """ Check if essential paths exist in path. Parameters ---------- path : str the bottle full path """ promise = ["dosdevices", "drive_c"] dirs = glob(f"{path}/*") dirs = [d.replace(f"{path}/", "") for d in dirs] for p in promise: if p not in dirs: raise ValueError("Given path doesn't seem a valid Bottle path.") return True def __load_config(self, path): """ Load config from path, if doesn't exists then create. Also update config structure if outdated. Parameters ---------- path : str the bottle full path """ try: file = open(f"{path}/bottle.json") self.config = json.load(file) file.close() except FileNotFoundError: file = open(f"{path}/bottle.json", "w") if len(self.config) == 0: config = self._config_struct config["Name"] = f"Generated {randint(10000, 20000)}" config["Path"] = path # TODO: set runner to latest installed json.dump(config, file, indent=4) self.config = json.load(file) else: config = self.config json.dump(config, file, indent=4) file.close() ''' Check for diffs. between _config_struct and the bottle one, then update. ''' missing_keys = self._config_struct.keys() - self.config.keys() for key in missing_keys: self.update_config( key=key, value=self._config_struct[key] ) missing_keys = ( self._config_struct["Parameters"].keys() - self.config["Parameters"].keys() ) for key in missing_keys: self.update_config( key=key, value=self._config_struct["Parameters"][key], scope="Parameters" ) ''' Wineprefix instance ''' def __set_wineprefix(self, runner_path: str = None): if not runner_path: runner_path = self.config["Runner"] self.wineprefix = Wine( winepath=runner_path, wineprefix=self.config["Path"], verbose=self.config["Verbose"] ) ''' Bottle config tools ''' def apply_environment(self, environment: int): if not self._environments[environment]: raise ValueError(f"{environment} is not a valid environment.") self.update_config( key="Environment", value=environment ) # TODO: work in progress return def apply_config(self, config: dict): for key, value in config.items(): self.update_config( key=key, value=value ) def update_config( self, key: str = None, value: str = None, scope: str = None): """ Update keys for a bottle config. Parameters ---------- key : str the key name value : str the value to be set scope : str (optional) where to look for the key if it is not the root (default is None) """ if scope is not None: self.config[scope][key] = value else: self.config[key] = value file = open( f"{self.config['Path']}/bottle.json", "w") json.dump(self.config, file, indent=4) file.close() ''' Bottle management ''' def rename(self, name: str): if not check_special_chars(text=name): return self.update_config( key="Name", value=name ) raise ValueError("The bottle name cannot contain special characters.") def set_runner(self): # TODO pass def set_versioning(self): # TODO pass def set_verbose(self, level: int): self.update_config( key="Verbose", value=level ) self.wineprefix.set_verbose(level) def set_dxvk_hud(self, status: bool): self.update_config( key="dxvk_hud", value=status, scope="Parameters" ) def set_sync(self, sync_type: int): if sync_type not in self._supported_sync_types: raise ValueError(f"{sync_type} is not a valid sync type.") self.update_config( key="sync", value=sync_type, scope="Parameters" ) def set_aco_compiler(self, status: bool): self.update_config( key="aco_compiler", value=status, scope="Parameters" ) def set_discrete_gpu(self, status: bool): self.update_config( key="discrete_gpu", value=status, scope="Parameters" ) def set_virtual_desktop(self, status: bool): self.update_config( key="virtual_desktop", value=status, scope="Parameters" ) if not status: self.wineprefix.set_virtual_desktop(False) def set_virtual_desktop_res(self, res: str): self.set_virtual_desktop(True) self.update_config( key="virtual_desktop_res", value=res, scope="Parameters" ) self.wineprefix.set_virtual_desktop( status=True, res=res ) def set_pulseaudio_latency(self, status: bool): self.update_config( key="pulseaudio_latency", value=status, scope="Parameters" )
Class variables
var config
var wineprefix
-
The base class of the class hierarchy.
When called, it accepts no arguments and returns a new featureless instance that has no instance attributes and cannot be given any.
Methods
def apply_config(self, config: dict)
-
Expand source code
def apply_config(self, config: dict): for key, value in config.items(): self.update_config( key=key, value=value )
def apply_environment(self, environment: int)
-
Expand source code
def apply_environment(self, environment: int): if not self._environments[environment]: raise ValueError(f"{environment} is not a valid environment.") self.update_config( key="Environment", value=environment ) # TODO: work in progress return
def rename(self, name: str)
-
Expand source code
def rename(self, name: str): if not check_special_chars(text=name): return self.update_config( key="Name", value=name ) raise ValueError("The bottle name cannot contain special characters.")
def set_aco_compiler(self, status: bool)
-
Expand source code
def set_aco_compiler(self, status: bool): self.update_config( key="aco_compiler", value=status, scope="Parameters" )
def set_discrete_gpu(self, status: bool)
-
Expand source code
def set_discrete_gpu(self, status: bool): self.update_config( key="discrete_gpu", value=status, scope="Parameters" )
def set_dxvk_hud(self, status: bool)
-
Expand source code
def set_dxvk_hud(self, status: bool): self.update_config( key="dxvk_hud", value=status, scope="Parameters" )
def set_pulseaudio_latency(self, status: bool)
-
Expand source code
def set_pulseaudio_latency(self, status: bool): self.update_config( key="pulseaudio_latency", value=status, scope="Parameters" )
def set_runner(self)
-
Expand source code
def set_runner(self): # TODO pass
def set_sync(self, sync_type: int)
-
Expand source code
def set_sync(self, sync_type: int): if sync_type not in self._supported_sync_types: raise ValueError(f"{sync_type} is not a valid sync type.") self.update_config( key="sync", value=sync_type, scope="Parameters" )
def set_verbose(self, level: int)
-
Expand source code
def set_verbose(self, level: int): self.update_config( key="Verbose", value=level ) self.wineprefix.set_verbose(level)
def set_versioning(self)
-
Expand source code
def set_versioning(self): # TODO pass
def set_virtual_desktop(self, status: bool)
-
Expand source code
def set_virtual_desktop(self, status: bool): self.update_config( key="virtual_desktop", value=status, scope="Parameters" ) if not status: self.wineprefix.set_virtual_desktop(False)
def set_virtual_desktop_res(self, res: str)
-
Expand source code
def set_virtual_desktop_res(self, res: str): self.set_virtual_desktop(True) self.update_config( key="virtual_desktop_res", value=res, scope="Parameters" ) self.wineprefix.set_virtual_desktop( status=True, res=res )
def update_config(self, key: str = None, value: str = None, scope: str = None)
-
Update keys for a bottle config.
Parameters
key
:str
- the key name
value
:str
- the value to be set
scope
:str (optional)
- where to look for the key if it is not the root (default is None)
Expand source code
def update_config( self, key: str = None, value: str = None, scope: str = None): """ Update keys for a bottle config. Parameters ---------- key : str the key name value : str the value to be set scope : str (optional) where to look for the key if it is not the root (default is None) """ if scope is not None: self.config[scope][key] = value else: self.config[key] = value file = open( f"{self.config['Path']}/bottle.json", "w") json.dump(self.config, file, indent=4) file.close()