while trace.tb_next:
trace = trace.tb_next
self.line = trace.tb_lineno
+ self.file_name = trace.tb_frame.f_code.co_filename
else:
try:
import inspect
- self.line = inspect.currentframe().f_back.f_lineno
+ frame = inspect.currentframe().f_back
+ self.line = frame.f_lineno
+ self.file_name = frame.f_code.co_filename
except:
self.line = None
+ self.file_name = None
self.original_exception = None
+ if os.path.abspath(self.file_name) == os.path.abspath(sys.argv[0]):
+ self.file_name = None
+
def __str__(self):
retval = [ self.message ]
if self.line:
- retval.append(" (line %d)" % self.line)
+ retval.append(" (line %d%s)" % (self.line, ("; %s" % self.file_name) if self.file_name else ""))
if self.original_exception:
retval.append(":\n ")
retval.append(str(self.original_exception).replace("\n", "\n "))
for line in configuration.split("\n"):
if line:
line = line.split(None, 1)
+ if line and line[0].startswith("#"):
+ continue
options[line[0]] = line[1] if len(line) > 1 else None
edid = None
if not os.path.isfile(config_name) or not os.path.isfile(setup_name):
continue
- edids = dict([ x.strip().split() for x in open(setup_name).readlines() if x.strip() ])
+ edids = dict([ x.split() for x in (y.strip() for y in open(setup_name).readlines()) if x and x[0] != "#" ])
config = {}
buffer = []
waits a second and then retries once. This mitigates #47,
a timing issue with some drivers.
"""
- kwargs_redirected = dict(kwargs)
- if hasattr(subprocess, "DEVNULL"):
- kwargs_redirected["stdout"] = getattr(subprocess, "DEVNULL")
+ if "dry_run" in kwargs:
+ dry_run = kwargs["dry_run"]
+ del kwargs["dry_run"]
else:
- kwargs_redirected["stdout"] = open(os.devnull, "w")
- kwargs_redirected["stderr"] = kwargs_redirected["stdout"]
+ dry_run = False
+ kwargs_redirected = dict(kwargs)
+ if not dry_run:
+ if hasattr(subprocess, "DEVNULL"):
+ kwargs_redirected["stdout"] = getattr(subprocess, "DEVNULL")
+ else:
+ kwargs_redirected["stdout"] = open(os.devnull, "w")
+ kwargs_redirected["stderr"] = kwargs_redirected["stdout"]
retval = subprocess.call(*args, **kwargs_redirected)
if retval != 0:
time.sleep(1)
# Perform pe-change auxiliary changes
if auxiliary_changes_pre:
argv = base_argv + list(chain.from_iterable(auxiliary_changes_pre))
- if call_and_retry(argv) != 0:
+ if call_and_retry(argv, dry_run=dry_run) != 0:
raise AutorandrException("Command failed: %s" % " ".join(argv))
# Disable unused outputs, but make sure that there always is at least one active screen
disable_keep = 0 if remain_active_count else 1
if len(disable_outputs) > disable_keep:
- if call_and_retry(base_argv + list(chain.from_iterable(disable_outputs[:-1] if disable_keep else disable_outputs))) != 0:
+ if call_and_retry(base_argv + list(chain.from_iterable(disable_outputs[:-1] if disable_keep else disable_outputs)), dry_run=dry_run) != 0:
# Disabling the outputs failed. Retry with the next command:
# Sometimes disabling of outputs fails due to an invalid RRSetScreenSize.
# This does not occur if simultaneously the primary screen is reset.
operations = disable_outputs + enable_outputs
for index in range(0, len(operations), 2):
argv = base_argv + list(chain.from_iterable(operations[index:index+2]))
- if call_and_retry(argv) != 0:
+ if call_and_retry(argv, dry_run=dry_run) != 0:
raise AutorandrException("Command failed: %s" % " ".join(argv))
def is_equal_configuration(source_configuration, target_configuration):
and system-wide configuration folders, named script_name or residing in
subdirectories named script_name.d.
+ If profile_path is None, only global scripts will be invoked.
+
meta_information is expected to be an dictionary. It will be passed to the block scripts
in the environment, as variables called AUTORANDR_<CAPITALIZED_KEY_HERE>.
if not os.path.isdir(user_profile_path):
user_profile_path = os.path.join(os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), "autorandr")
- for folder in chain((profile_path, os.path.dirname(profile_path), user_profile_path),
- (os.path.join(x, "autorandr") for x in os.environ.get("XDG_CONFIG_DIRS", "/etc/xdg").split(":"))):
+ candidate_directories = chain((user_profile_path,), (os.path.join(x, "autorandr") for x in os.environ.get("XDG_CONFIG_DIRS", "/etc/xdg").split(":")))
+ if profile_path:
+ candidate_directories = chain((profile_path,), candidate_directories)
+
+ for folder in candidate_directories:
if script_name not in ran_scripts:
script = os.path.join(folder, script_name)
if os.access(script, os.X_OK | os.F_OK):
- all_ok &= subprocess.call(script, env=env) != 0
+ try:
+ all_ok &= subprocess.call(script, env=env) != 0
+ except:
+ raise AutorandrException("Failed to execute user command: %s" % (script,))
ran_scripts.add(script_name)
script_folder = os.path.join(folder, "%s.d" % script_name)
if check_name not in ran_scripts:
script = os.path.join(script_folder, file_name)
if os.access(script, os.X_OK | os.F_OK):
- all_ok &= subprocess.call(script, env=env) != 0
+ try:
+ all_ok &= subprocess.call(script, env=env) != 0
+ except:
+ raise AutorandrException("Failed to execute user command: %s" % (script,))
ran_scripts.add(check_name)
return all_ok
process_environ[name] = value
display = process_environ["DISPLAY"] if "DISPLAY" in process_environ else None
+ # To allow scripts to detect batch invocation (especially useful for predetect)
+ process_environ["AUTORANDR_BATCH_PID"] = str(os.getpid())
+
if display and display not in X11_displays_done:
try:
pwent = pwd.getpwuid(uid)
file=sys.stderr)
sys.exit(posix.EX_USAGE)
+ if "-h" in options or "--help" in options:
+ exit_help()
+
# Batch mode
if "--batch" in options:
if ("DISPLAY" not in os.environ or not os.environ["DISPLAY"]) and os.getuid() == 0:
profile_symlinks = { k: v for k, v in profile_symlinks.items() if v in (x[0] for x in virtual_profiles) or v in profiles }
+ exec_scripts(None, "predetect")
config, modes = parse_xrandr_output()
if "--fingerprint" in options:
raise AutorandrException("Failed to remove profile '%s'" % (options["--remove"],), e)
sys.exit(0)
- if "-h" in options or "--help" in options:
- exit_help()
-
detected_profiles = find_profiles(config, profiles)
load_profile = False
apply_configuration(load_config, config, True)
apply_configuration(load_config, config, False)
exec_scripts(scripts_path, "postswitch", script_metadata)
+ except AutorandrException as e:
+ raise AutorandrException("Failed to apply profile '%s'" % load_profile, e, e.report_bug)
except Exception as e:
raise AutorandrException("Failed to apply profile '%s'" % load_profile, e, True)