mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-06-17 00:07:37 +02:00
New parser: xrandr
Tests passing, working as intended in plugin directory
This commit is contained in:
353
jc/parsers/xrandr.py
Normal file
353
jc/parsers/xrandr.py
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
"""jc - JSON CLI output utility `xrandr` command output parser
|
||||||
|
|
||||||
|
Options supported:
|
||||||
|
|
||||||
|
Usage (module):
|
||||||
|
|
||||||
|
import jc.parsers.xrandr
|
||||||
|
result = jc.parsers.xrandr.parse(xrandr_command_output)
|
||||||
|
|
||||||
|
Schema:
|
||||||
|
{
|
||||||
|
"screens": [
|
||||||
|
{
|
||||||
|
"screen_number": 0,
|
||||||
|
"minimum_width": 8,
|
||||||
|
"minimum_height": 8,
|
||||||
|
"current_width": 1920,
|
||||||
|
"current_height": 1080,
|
||||||
|
"maximum_width": 32767,
|
||||||
|
"maximum_height": 32767,
|
||||||
|
"associated_device": {
|
||||||
|
"associated_modes": [
|
||||||
|
{
|
||||||
|
"resolution_width": 1920,
|
||||||
|
"resolution_height": 1080,
|
||||||
|
"is_high_resolution": false,
|
||||||
|
"frequencies": [
|
||||||
|
{
|
||||||
|
"frequency": 60.03,
|
||||||
|
"is_current": true,
|
||||||
|
"is_preferred": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frequency": 59.93,
|
||||||
|
"is_current": false,
|
||||||
|
"is_preferred": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resolution_width": 1680,
|
||||||
|
"resolution_height": 1050,
|
||||||
|
"is_high_resolution": false,
|
||||||
|
"frequencies": [
|
||||||
|
{
|
||||||
|
"frequency": 59.88,
|
||||||
|
"is_current": false,
|
||||||
|
"is_preferred": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"is_connected": true,
|
||||||
|
"is_primary": true,
|
||||||
|
"device_name": "eDP1",
|
||||||
|
"resolution_width": 1920,
|
||||||
|
"resolution_height": 1080,
|
||||||
|
"offset_width": 0,
|
||||||
|
"offset_height": 0,
|
||||||
|
"dimension_width": 310,
|
||||||
|
"dimension_height": 170
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unassociated_devices": []
|
||||||
|
}
|
||||||
|
Translated from:
|
||||||
|
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
|
||||||
|
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm
|
||||||
|
1920x1080 60.03*+ 59.93
|
||||||
|
1680x1050 59.88
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ xrandr | jc --xrandr
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from typing import Dict, List, Iterator, Optional, Union
|
||||||
|
|
||||||
|
import jc.utils
|
||||||
|
|
||||||
|
|
||||||
|
class info:
|
||||||
|
"""Provides parser metadata (version, author, etc.)"""
|
||||||
|
|
||||||
|
version = "1.9"
|
||||||
|
description = "`xrandr` command parser"
|
||||||
|
author = "Kevin Lyter"
|
||||||
|
author_email = "lyter_git at sent.com"
|
||||||
|
|
||||||
|
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||||
|
compatible = ["linux", "darwin", "cygwin", "aix", "freebsd"]
|
||||||
|
magic_commands = ["xrandr"]
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = info.version
|
||||||
|
|
||||||
|
# ScreenLine = Dict[str, int]
|
||||||
|
# DeviceLine = Dict[str, int | bool | str]
|
||||||
|
# ModeLine = Dict[str, int]
|
||||||
|
|
||||||
|
try:
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
Frequency = TypedDict(
|
||||||
|
"Frequency",
|
||||||
|
{
|
||||||
|
"frequency": float,
|
||||||
|
"is_current": bool,
|
||||||
|
"is_preferred": bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Mode = TypedDict(
|
||||||
|
"Mode",
|
||||||
|
{
|
||||||
|
"resolution_width": int,
|
||||||
|
"resolution_height": int,
|
||||||
|
"is_high_resolution": bool,
|
||||||
|
"frequencies": List[Frequency],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Device = TypedDict(
|
||||||
|
"Device",
|
||||||
|
{
|
||||||
|
"device_name": str,
|
||||||
|
"is_connected": bool,
|
||||||
|
"is_primary": bool,
|
||||||
|
"resolution_width": int,
|
||||||
|
"resolution_height": int,
|
||||||
|
"offset_width": int,
|
||||||
|
"offset_height": int,
|
||||||
|
"dimension_width": int,
|
||||||
|
"dimension_height": int,
|
||||||
|
"associated_modes": List[Mode],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Screen = TypedDict(
|
||||||
|
"Screen",
|
||||||
|
{
|
||||||
|
"screen_number": int,
|
||||||
|
"minimum_width": int,
|
||||||
|
"minimum_height": int,
|
||||||
|
"current_width": int,
|
||||||
|
"current_height": int,
|
||||||
|
"maximum_width": int,
|
||||||
|
"maximum_height": int,
|
||||||
|
"associated_device": Device,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Response = TypedDict(
|
||||||
|
"Response",
|
||||||
|
{
|
||||||
|
"screens": List[Screen],
|
||||||
|
"unassociated_devices": List[Device],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except ImportError:
|
||||||
|
Screen = Dict[str, int | str]
|
||||||
|
Device = Dict[str, str | int | bool]
|
||||||
|
Frequency = Dict[str, float | bool]
|
||||||
|
Mode = Dict[str, int | bool | List[Frequency]]
|
||||||
|
Response = Dict[str, Device | Mode | Screen]
|
||||||
|
|
||||||
|
|
||||||
|
def _process(proc_data):
|
||||||
|
"""
|
||||||
|
Final processing to conform to the schema.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
proc_data: (List of Dictionaries) raw structured data to process
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
List of Dictionaries. Structured data to conform to the schema.
|
||||||
|
"""
|
||||||
|
for entry in proc_data:
|
||||||
|
int_list = ["links", "size"]
|
||||||
|
for key in entry:
|
||||||
|
if key in int_list:
|
||||||
|
entry[key] = jc.utils.convert_to_int(entry[key])
|
||||||
|
|
||||||
|
if "date" in entry:
|
||||||
|
# to speed up processing only try to convert the date if it's not the default format
|
||||||
|
if not re.match(
|
||||||
|
r"[a-zA-Z]{3}\s{1,2}\d{1,2}\s{1,2}[0-9:]{4,5}", entry["date"]
|
||||||
|
):
|
||||||
|
ts = jc.utils.timestamp(entry["date"])
|
||||||
|
entry["epoch"] = ts.naive
|
||||||
|
entry["epoch_utc"] = ts.utc
|
||||||
|
|
||||||
|
return proc_data
|
||||||
|
|
||||||
|
|
||||||
|
_screen_pattern = (
|
||||||
|
r"Screen (?P<screen_number>\d+): "
|
||||||
|
+ "minimum (?P<minimum_width>\d+) x (?P<minimum_height>\d+), "
|
||||||
|
+ "current (?P<current_width>\d+) x (?P<current_height>\d+), "
|
||||||
|
+ "maximum (?P<maximum_width>\d+) x (?P<maximum_height>\d+)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_screen(next_lines: List[str]) -> Optional[Screen]:
|
||||||
|
next_line = next_lines.pop()
|
||||||
|
result = re.match(_screen_pattern, next_line)
|
||||||
|
if not result:
|
||||||
|
next_lines.append(next_line)
|
||||||
|
return None
|
||||||
|
|
||||||
|
raw_matches = result.groupdict()
|
||||||
|
screen: Screen = {}
|
||||||
|
for k, v in raw_matches.items():
|
||||||
|
screen[k] = int(v)
|
||||||
|
|
||||||
|
if next_lines:
|
||||||
|
device: Optional[Device] = _parse_device(next_lines)
|
||||||
|
if device:
|
||||||
|
screen["associated_device"] = device
|
||||||
|
|
||||||
|
return screen
|
||||||
|
|
||||||
|
|
||||||
|
# eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis)
|
||||||
|
# 310mm x 170mm
|
||||||
|
# regex101 demo link
|
||||||
|
# https://regex101.com/r/5ZQEDC/1
|
||||||
|
_device_pattern = (
|
||||||
|
r"(?P<device_name>.+) "
|
||||||
|
+ "(?P<is_connected>(connected|disconnected)) ?"
|
||||||
|
+ "(?P<is_primary> primary)? ?"
|
||||||
|
+ "((?P<resolution_width>\d+)x(?P<resolution_height>\d+)"
|
||||||
|
+ "\+(?P<offset_width>\d+)\+(?P<offset_height>\d+))? "
|
||||||
|
+ "\(normal left inverted right x axis y axis\)"
|
||||||
|
+ "( ((?P<dimension_width>\d+)mm x (?P<dimension_height>\d+)mm)?)?"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_device(next_lines: List[str]) -> Optional[Device]:
|
||||||
|
if not next_lines:
|
||||||
|
return None
|
||||||
|
|
||||||
|
next_line = next_lines.pop()
|
||||||
|
result = re.match(_device_pattern, next_line)
|
||||||
|
if not result:
|
||||||
|
next_lines.append(next_line)
|
||||||
|
return None
|
||||||
|
|
||||||
|
matches = result.groupdict()
|
||||||
|
|
||||||
|
device: Device = {
|
||||||
|
"associated_modes": [],
|
||||||
|
"is_connected": matches["is_connected"] == "connected",
|
||||||
|
"is_primary": matches["is_primary"] is not None
|
||||||
|
and len(matches["is_primary"]) > 0,
|
||||||
|
"device_name": matches["device_name"],
|
||||||
|
}
|
||||||
|
for k, v in matches.items():
|
||||||
|
if k not in {"is_connected", "is_primary", "device_name"}:
|
||||||
|
try:
|
||||||
|
if v:
|
||||||
|
device[k] = int(v)
|
||||||
|
except ValueError:
|
||||||
|
print(f"Error: {next_line} : {k} - {v} is not int-able")
|
||||||
|
|
||||||
|
while next_lines:
|
||||||
|
next_line = next_lines.pop()
|
||||||
|
next_mode: Optional[Mode] = _parse_mode(next_line)
|
||||||
|
if next_mode:
|
||||||
|
device["associated_modes"].append(next_mode)
|
||||||
|
else:
|
||||||
|
next_lines.append(next_line)
|
||||||
|
break
|
||||||
|
return device
|
||||||
|
|
||||||
|
|
||||||
|
# 1920x1080i 60.03*+ 59.93
|
||||||
|
# 1920x1080 60.00 + 50.00 59.94
|
||||||
|
_mode_pattern = r"\s*(?P<resolution_width>\d+)x(?P<resolution_height>\d+)(?P<is_high_resolution>i)?\s+(?P<rest>.*)"
|
||||||
|
_frequencies_pattern = r"(((?P<frequency>\d+\.\d+)(?P<star>\*| |)(?P<plus>\+?)?)+)"
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_mode(line: str) -> Optional[Mode]:
|
||||||
|
result = re.match(_mode_pattern, line)
|
||||||
|
frequencies: List[Frequency] = []
|
||||||
|
if not result:
|
||||||
|
return None
|
||||||
|
|
||||||
|
d = result.groupdict()
|
||||||
|
resolution_width = int(d["resolution_width"])
|
||||||
|
resolution_height = int(d["resolution_height"])
|
||||||
|
is_high_resolution = d["is_high_resolution"] is not None
|
||||||
|
|
||||||
|
mode: Mode = {
|
||||||
|
"resolution_width": resolution_width,
|
||||||
|
"resolution_height": resolution_height,
|
||||||
|
"is_high_resolution": is_high_resolution,
|
||||||
|
"frequencies": frequencies,
|
||||||
|
}
|
||||||
|
|
||||||
|
result = re.finditer(_frequencies_pattern, d["rest"])
|
||||||
|
if not result:
|
||||||
|
return mode
|
||||||
|
|
||||||
|
for match in result:
|
||||||
|
d = match.groupdict()
|
||||||
|
frequency = float(d["frequency"])
|
||||||
|
is_current = len(d["star"]) > 0
|
||||||
|
is_preferred = len(d["plus"]) > 0
|
||||||
|
f: Frequency = {
|
||||||
|
"frequency": frequency,
|
||||||
|
"is_current": is_current,
|
||||||
|
"is_preferred": is_preferred,
|
||||||
|
}
|
||||||
|
mode["frequencies"].append(f)
|
||||||
|
return mode
|
||||||
|
|
||||||
|
|
||||||
|
def parse(data: str, raw=False, quiet=False):
|
||||||
|
"""
|
||||||
|
Main text parsing function
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
data: (string) text data to parse
|
||||||
|
raw: (boolean) output preprocessed JSON if True
|
||||||
|
quiet: (boolean) suppress warning messages if True
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
List of Dictionaries. Raw or processed structured data.
|
||||||
|
"""
|
||||||
|
if not quiet:
|
||||||
|
jc.utils.compatibility(__name__, info.compatible)
|
||||||
|
|
||||||
|
warned = False
|
||||||
|
parent = ""
|
||||||
|
next_is_parent = False
|
||||||
|
new_section = False
|
||||||
|
|
||||||
|
linedata = data.splitlines()
|
||||||
|
linedata.reverse() # For popping
|
||||||
|
|
||||||
|
result: Response = {"screens": [], "unassociated_devices": []}
|
||||||
|
if jc.utils.has_data(data):
|
||||||
|
result: Response = {"screens": [], "unassociated_devices": []}
|
||||||
|
while linedata:
|
||||||
|
screen = _parse_screen(linedata)
|
||||||
|
if screen:
|
||||||
|
result["screens"].append(screen)
|
||||||
|
else:
|
||||||
|
device = _parse_device(linedata)
|
||||||
|
if device:
|
||||||
|
result["unassociated_devices"].append(device)
|
||||||
|
return result
|
38
templates/xrandr_sample.txt
Normal file
38
templates/xrandr_sample.txt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
|
||||||
|
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm
|
||||||
|
1920x1080 60.03*+ 59.93
|
||||||
|
1680x1050 59.88
|
||||||
|
1400x1050 59.98
|
||||||
|
1600x900 60.00 59.95 59.82
|
||||||
|
1280x1024 60.02
|
||||||
|
1400x900 59.96 59.88
|
||||||
|
1280x960 60.00
|
||||||
|
1368x768 60.00 59.88 59.85
|
||||||
|
1280x800 59.81 59.91
|
||||||
|
1280x720 59.86 60.00 59.74
|
||||||
|
1024x768 60.00
|
||||||
|
1024x576 60.00 59.90 59.82
|
||||||
|
960x540 60.00 59.63 59.82
|
||||||
|
800x600 60.32 56.25
|
||||||
|
864x486 60.00 59.92 59.57
|
||||||
|
640x480 59.94
|
||||||
|
720x405 59.51 60.00 58.99
|
||||||
|
640x360 59.84 59.32 60.00
|
||||||
|
DP1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
DP2 disconnected (normal left inverted right x axis y axis)
|
||||||
|
HDMI1 connected (normal left inverted right x axis y axis)
|
||||||
|
1920x1080 60.00 + 50.00 59.94
|
||||||
|
1920x1080i 60.00 50.00 59.94
|
||||||
|
1680x1050 59.88
|
||||||
|
1280x1024 75.02 60.02
|
||||||
|
1440x900 59.90
|
||||||
|
1280x960 60.00
|
||||||
|
1280x720 60.00 50.00 59.94
|
||||||
|
1024x768 75.03 70.07 60.00
|
||||||
|
832x624 74.55
|
||||||
|
800x600 72.19 75.00 60.32 56.25
|
||||||
|
720x576 50.00
|
||||||
|
720x480 60.00 59.94
|
||||||
|
640x480 75.00 72.81 66.67 60.00 59.94
|
||||||
|
720x400 70.08
|
||||||
|
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
|
249
templates/xrandr_sample_verbose.txt
Normal file
249
templates/xrandr_sample_verbose.txt
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
|
||||||
|
eDP1 connected primary 1920x1080+0+0 (0x49) normal (normal left inverted right x axis y axis) 310mm x 170mm
|
||||||
|
Identifier: 0x43
|
||||||
|
Timestamp: 910112952
|
||||||
|
Subpixel: unknown
|
||||||
|
Gamma: 1.0:1.0:1.0
|
||||||
|
Brightness: 1.0
|
||||||
|
Clones:
|
||||||
|
CRTC: 0
|
||||||
|
CRTCs: 0 1 2
|
||||||
|
Transform: 1.000000 0.000000 0.000000
|
||||||
|
0.000000 1.000000 0.000000
|
||||||
|
0.000000 0.000000 1.000000
|
||||||
|
filter:
|
||||||
|
EDID:
|
||||||
|
00ffffffffffff0006af3d5700000000
|
||||||
|
001c0104a51f1178022285a5544d9a27
|
||||||
|
0e505400000001010101010101010101
|
||||||
|
010101010101b43780a070383e401010
|
||||||
|
350035ae100000180000000f00000000
|
||||||
|
00000000000000000020000000fe0041
|
||||||
|
554f0a202020202020202020000000fe
|
||||||
|
004231343048414e30352e37200a0070
|
||||||
|
BACKLIGHT: 19394
|
||||||
|
range: (0, 24242)
|
||||||
|
Backlight: 19394
|
||||||
|
range: (0, 24242)
|
||||||
|
scaling mode: Full aspect
|
||||||
|
supported: Full, Center, Full aspect
|
||||||
|
Colorspace: Default
|
||||||
|
supported: Default, RGB_Wide_Gamut_Fixed_Point, RGB_Wide_Gamut_Floating_Point, opRGB, DCI-P3_RGB_D65, BT2020_RGB, BT601_YCC, BT709_YCC, XVYCC_601, XVYCC_709, SYCC_601, opYCC_601, BT2020_CYCC, BT2020_YCC
|
||||||
|
max bpc: 12
|
||||||
|
range: (6, 12)
|
||||||
|
Broadcast RGB: Automatic
|
||||||
|
supported: Automatic, Full, Limited 16:235
|
||||||
|
panel orientation: Normal
|
||||||
|
supported: Normal, Upside Down, Left Side Up, Right Side Up
|
||||||
|
link-status: Good
|
||||||
|
supported: Good, Bad
|
||||||
|
non-desktop: 0
|
||||||
|
range: (0, 1)
|
||||||
|
1920x1080 (0x49) 142.600MHz -HSync -VSync *current +preferred
|
||||||
|
h: width 1920 start 1936 end 1952 total 2080 skew 0 clock 68.56KHz
|
||||||
|
v: height 1080 start 1083 end 1088 total 1142 clock 60.03Hz
|
||||||
|
1920x1080 (0x1b5) 138.500MHz +HSync -VSync
|
||||||
|
h: width 1920 start 1968 end 2000 total 2080 skew 0 clock 66.59KHz
|
||||||
|
v: height 1080 start 1083 end 1088 total 1111 clock 59.93Hz
|
||||||
|
1680x1050 (0x1b6) 119.000MHz +HSync -VSync
|
||||||
|
h: width 1680 start 1728 end 1760 total 1840 skew 0 clock 64.67KHz
|
||||||
|
v: height 1050 start 1053 end 1059 total 1080 clock 59.88Hz
|
||||||
|
1400x1050 (0x1b7) 122.000MHz +HSync +VSync
|
||||||
|
h: width 1400 start 1488 end 1640 total 1880 skew 0 clock 64.89KHz
|
||||||
|
v: height 1050 start 1052 end 1064 total 1082 clock 59.98Hz
|
||||||
|
1600x900 (0x1b8) 118.997MHz -HSync +VSync
|
||||||
|
h: width 1600 start 1696 end 1864 total 2128 skew 0 clock 55.92KHz
|
||||||
|
v: height 900 start 901 end 904 total 932 clock 60.00Hz
|
||||||
|
1600x900 (0x1b9) 118.250MHz -HSync +VSync
|
||||||
|
h: width 1600 start 1696 end 1856 total 2112 skew 0 clock 55.99KHz
|
||||||
|
v: height 900 start 903 end 908 total 934 clock 59.95Hz
|
||||||
|
1600x900 (0x1ba) 97.500MHz +HSync -VSync
|
||||||
|
h: width 1600 start 1648 end 1680 total 1760 skew 0 clock 55.40KHz
|
||||||
|
v: height 900 start 903 end 908 total 926 clock 59.82Hz
|
||||||
|
1280x1024 (0x1bb) 108.000MHz +HSync +VSync
|
||||||
|
h: width 1280 start 1328 end 1440 total 1688 skew 0 clock 63.98KHz
|
||||||
|
v: height 1024 start 1025 end 1028 total 1066 clock 60.02Hz
|
||||||
|
1400x900 (0x1bc) 103.500MHz -HSync +VSync
|
||||||
|
h: width 1400 start 1480 end 1624 total 1848 skew 0 clock 56.01KHz
|
||||||
|
v: height 900 start 903 end 913 total 934 clock 59.96Hz
|
||||||
|
1400x900 (0x1bd) 86.500MHz +HSync -VSync
|
||||||
|
h: width 1400 start 1448 end 1480 total 1560 skew 0 clock 55.45KHz
|
||||||
|
v: height 900 start 903 end 913 total 926 clock 59.88Hz
|
||||||
|
1280x960 (0x1be) 108.000MHz +HSync +VSync
|
||||||
|
h: width 1280 start 1376 end 1488 total 1800 skew 0 clock 60.00KHz
|
||||||
|
v: height 960 start 961 end 964 total 1000 clock 60.00Hz
|
||||||
|
1368x768 (0x1bf) 85.860MHz -HSync +VSync
|
||||||
|
h: width 1368 start 1440 end 1584 total 1800 skew 0 clock 47.70KHz
|
||||||
|
v: height 768 start 769 end 772 total 795 clock 60.00Hz
|
||||||
|
1368x768 (0x1c0) 85.250MHz -HSync +VSync
|
||||||
|
h: width 1368 start 1440 end 1576 total 1784 skew 0 clock 47.79KHz
|
||||||
|
v: height 768 start 771 end 781 total 798 clock 59.88Hz
|
||||||
|
1368x768 (0x1c1) 72.250MHz +HSync -VSync
|
||||||
|
h: width 1368 start 1416 end 1448 total 1528 skew 0 clock 47.28KHz
|
||||||
|
v: height 768 start 771 end 781 total 790 clock 59.85Hz
|
||||||
|
1280x800 (0x1c2) 83.500MHz -HSync +VSync
|
||||||
|
h: width 1280 start 1352 end 1480 total 1680 skew 0 clock 49.70KHz
|
||||||
|
v: height 800 start 803 end 809 total 831 clock 59.81Hz
|
||||||
|
1280x800 (0x1c3) 71.000MHz +HSync -VSync
|
||||||
|
h: width 1280 start 1328 end 1360 total 1440 skew 0 clock 49.31KHz
|
||||||
|
v: height 800 start 803 end 809 total 823 clock 59.91Hz
|
||||||
|
1280x720 (0x1c4) 74.500MHz -HSync +VSync
|
||||||
|
h: width 1280 start 1344 end 1472 total 1664 skew 0 clock 44.77KHz
|
||||||
|
v: height 720 start 723 end 728 total 748 clock 59.86Hz
|
||||||
|
1280x720 (0x1c5) 74.480MHz -HSync +VSync
|
||||||
|
h: width 1280 start 1336 end 1472 total 1664 skew 0 clock 44.76KHz
|
||||||
|
v: height 720 start 721 end 724 total 746 clock 60.00Hz
|
||||||
|
1280x720 (0x1c6) 63.750MHz +HSync -VSync
|
||||||
|
h: width 1280 start 1328 end 1360 total 1440 skew 0 clock 44.27KHz
|
||||||
|
v: height 720 start 723 end 728 total 741 clock 59.74Hz
|
||||||
|
1024x768 (0x1c7) 65.000MHz -HSync -VSync
|
||||||
|
h: width 1024 start 1048 end 1184 total 1344 skew 0 clock 48.36KHz
|
||||||
|
v: height 768 start 771 end 777 total 806 clock 60.00Hz
|
||||||
|
1024x576 (0x1c8) 46.995MHz -HSync +VSync
|
||||||
|
h: width 1024 start 1064 end 1168 total 1312 skew 0 clock 35.82KHz
|
||||||
|
v: height 576 start 577 end 580 total 597 clock 60.00Hz
|
||||||
|
1024x576 (0x1c9) 46.500MHz -HSync +VSync
|
||||||
|
h: width 1024 start 1064 end 1160 total 1296 skew 0 clock 35.88KHz
|
||||||
|
v: height 576 start 579 end 584 total 599 clock 59.90Hz
|
||||||
|
1024x576 (0x1ca) 42.000MHz +HSync -VSync
|
||||||
|
h: width 1024 start 1072 end 1104 total 1184 skew 0 clock 35.47KHz
|
||||||
|
v: height 576 start 579 end 584 total 593 clock 59.82Hz
|
||||||
|
960x540 (0x1cb) 40.784MHz -HSync +VSync
|
||||||
|
h: width 960 start 992 end 1088 total 1216 skew 0 clock 33.54KHz
|
||||||
|
v: height 540 start 541 end 544 total 559 clock 60.00Hz
|
||||||
|
960x540 (0x1cc) 40.750MHz -HSync +VSync
|
||||||
|
h: width 960 start 992 end 1088 total 1216 skew 0 clock 33.51KHz
|
||||||
|
v: height 540 start 543 end 548 total 562 clock 59.63Hz
|
||||||
|
960x540 (0x1cd) 37.250MHz +HSync -VSync
|
||||||
|
h: width 960 start 1008 end 1040 total 1120 skew 0 clock 33.26KHz
|
||||||
|
v: height 540 start 543 end 548 total 556 clock 59.82Hz
|
||||||
|
800x600 (0x1ce) 40.000MHz +HSync +VSync
|
||||||
|
h: width 800 start 840 end 968 total 1056 skew 0 clock 37.88KHz
|
||||||
|
v: height 600 start 601 end 605 total 628 clock 60.32Hz
|
||||||
|
800x600 (0x1cf) 36.000MHz +HSync +VSync
|
||||||
|
h: width 800 start 824 end 896 total 1024 skew 0 clock 35.16KHz
|
||||||
|
v: height 600 start 601 end 603 total 625 clock 56.25Hz
|
||||||
|
864x486 (0x1d0) 32.901MHz -HSync +VSync
|
||||||
|
h: width 864 start 888 end 976 total 1088 skew 0 clock 30.24KHz
|
||||||
|
v: height 486 start 487 end 490 total 504 clock 60.00Hz
|
||||||
|
864x486 (0x1d1) 32.500MHz -HSync +VSync
|
||||||
|
h: width 864 start 888 end 968 total 1072 skew 0 clock 30.32KHz
|
||||||
|
v: height 486 start 489 end 494 total 506 clock 59.92Hz
|
||||||
|
864x486 (0x1d2) 30.500MHz +HSync -VSync
|
||||||
|
h: width 864 start 912 end 944 total 1024 skew 0 clock 29.79KHz
|
||||||
|
v: height 486 start 489 end 494 total 500 clock 59.57Hz
|
||||||
|
640x480 (0x1d3) 25.175MHz -HSync -VSync
|
||||||
|
h: width 640 start 656 end 752 total 800 skew 0 clock 31.47KHz
|
||||||
|
v: height 480 start 490 end 492 total 525 clock 59.94Hz
|
||||||
|
720x405 (0x1d4) 22.500MHz -HSync +VSync
|
||||||
|
h: width 720 start 744 end 808 total 896 skew 0 clock 25.11KHz
|
||||||
|
v: height 405 start 408 end 413 total 422 clock 59.51Hz
|
||||||
|
720x405 (0x1d5) 22.176MHz -HSync +VSync
|
||||||
|
h: width 720 start 728 end 800 total 880 skew 0 clock 25.20KHz
|
||||||
|
v: height 405 start 406 end 409 total 420 clock 60.00Hz
|
||||||
|
720x405 (0x1d6) 21.750MHz +HSync -VSync
|
||||||
|
h: width 720 start 768 end 800 total 880 skew 0 clock 24.72KHz
|
||||||
|
v: height 405 start 408 end 413 total 419 clock 58.99Hz
|
||||||
|
640x360 (0x1d7) 18.000MHz -HSync +VSync
|
||||||
|
h: width 640 start 664 end 720 total 800 skew 0 clock 22.50KHz
|
||||||
|
v: height 360 start 363 end 368 total 376 clock 59.84Hz
|
||||||
|
640x360 (0x1d8) 17.750MHz +HSync -VSync
|
||||||
|
h: width 640 start 688 end 720 total 800 skew 0 clock 22.19KHz
|
||||||
|
v: height 360 start 363 end 368 total 374 clock 59.32Hz
|
||||||
|
640x360 (0x1d9) 17.187MHz -HSync +VSync
|
||||||
|
h: width 640 start 640 end 704 total 768 skew 0 clock 22.38KHz
|
||||||
|
v: height 360 start 361 end 364 total 373 clock 60.00Hz
|
||||||
|
DP1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
Identifier: 0x44
|
||||||
|
Timestamp: 910112952
|
||||||
|
Subpixel: unknown
|
||||||
|
Clones: HDMI1
|
||||||
|
CRTCs: 0 1 2
|
||||||
|
Transform: 1.000000 0.000000 0.000000
|
||||||
|
0.000000 1.000000 0.000000
|
||||||
|
0.000000 0.000000 1.000000
|
||||||
|
filter:
|
||||||
|
HDCP Content Type: HDCP Type0
|
||||||
|
supported: HDCP Type0, HDCP Type1
|
||||||
|
Content Protection: Undesired
|
||||||
|
supported: Undesired, Desired, Enabled
|
||||||
|
Colorspace: Default
|
||||||
|
supported: Default, RGB_Wide_Gamut_Fixed_Point, RGB_Wide_Gamut_Floating_Point, opRGB, DCI-P3_RGB_D65, BT2020_RGB, BT601_YCC, BT709_YCC, XVYCC_601, XVYCC_709, SYCC_601, opYCC_601, BT2020_CYCC, BT2020_YCC
|
||||||
|
max bpc: 12
|
||||||
|
range: (6, 12)
|
||||||
|
Broadcast RGB: Automatic
|
||||||
|
supported: Automatic, Full, Limited 16:235
|
||||||
|
audio: auto
|
||||||
|
supported: force-dvi, off, auto, on
|
||||||
|
link-status: Good
|
||||||
|
supported: Good, Bad
|
||||||
|
non-desktop: 0
|
||||||
|
range: (0, 1)
|
||||||
|
DP2 disconnected (normal left inverted right x axis y axis)
|
||||||
|
Identifier: 0x45
|
||||||
|
Timestamp: 910112952
|
||||||
|
Subpixel: unknown
|
||||||
|
Clones:
|
||||||
|
CRTCs: 0 1 2
|
||||||
|
Transform: 1.000000 0.000000 0.000000
|
||||||
|
0.000000 1.000000 0.000000
|
||||||
|
0.000000 0.000000 1.000000
|
||||||
|
filter:
|
||||||
|
HDCP Content Type: HDCP Type0
|
||||||
|
supported: HDCP Type0, HDCP Type1
|
||||||
|
Content Protection: Undesired
|
||||||
|
supported: Undesired, Desired, Enabled
|
||||||
|
Colorspace: Default
|
||||||
|
supported: Default, RGB_Wide_Gamut_Fixed_Point, RGB_Wide_Gamut_Floating_Point, opRGB, DCI-P3_RGB_D65, BT2020_RGB, BT601_YCC, BT709_YCC, XVYCC_601, XVYCC_709, SYCC_601, opYCC_601, BT2020_CYCC, BT2020_YCC
|
||||||
|
max bpc: 12
|
||||||
|
range: (6, 12)
|
||||||
|
Broadcast RGB: Automatic
|
||||||
|
supported: Automatic, Full, Limited 16:235
|
||||||
|
audio: auto
|
||||||
|
supported: force-dvi, off, auto, on
|
||||||
|
link-status: Good
|
||||||
|
supported: Good, Bad
|
||||||
|
non-desktop: 0
|
||||||
|
range: (0, 1)
|
||||||
|
HDMI1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
Identifier: 0x46
|
||||||
|
Timestamp: 910112952
|
||||||
|
Subpixel: unknown
|
||||||
|
Clones: DP1
|
||||||
|
CRTCs: 0 1 2
|
||||||
|
Transform: 1.000000 0.000000 0.000000
|
||||||
|
0.000000 1.000000 0.000000
|
||||||
|
0.000000 0.000000 1.000000
|
||||||
|
filter:
|
||||||
|
HDCP Content Type: HDCP Type0
|
||||||
|
supported: HDCP Type0, HDCP Type1
|
||||||
|
Content Protection: Undesired
|
||||||
|
supported: Undesired, Desired, Enabled
|
||||||
|
max bpc: 12
|
||||||
|
range: (8, 12)
|
||||||
|
content type: No Data
|
||||||
|
supported: No Data, Graphics, Photo, Cinema, Game
|
||||||
|
Colorspace: Default
|
||||||
|
supported: Default, SMPTE_170M_YCC, BT709_YCC, XVYCC_601, XVYCC_709, SYCC_601, opYCC_601, opRGB, BT2020_CYCC, BT2020_RGB, BT2020_YCC, DCI-P3_RGB_D65, DCI-P3_RGB_Theater
|
||||||
|
aspect ratio: Automatic
|
||||||
|
supported: Automatic, 4:3, 16:9
|
||||||
|
Broadcast RGB: Automatic
|
||||||
|
supported: Automatic, Full, Limited 16:235
|
||||||
|
audio: auto
|
||||||
|
supported: force-dvi, off, auto, on
|
||||||
|
link-status: Good
|
||||||
|
supported: Good, Bad
|
||||||
|
non-desktop: 0
|
||||||
|
range: (0, 1)
|
||||||
|
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
Identifier: 0x47
|
||||||
|
Timestamp: 910112952
|
||||||
|
Subpixel: no subpixels
|
||||||
|
Clones:
|
||||||
|
CRTCs: 3
|
||||||
|
Transform: 1.000000 0.000000 0.000000
|
||||||
|
0.000000 1.000000 0.000000
|
||||||
|
0.000000 0.000000 1.000000
|
||||||
|
filter:
|
||||||
|
non-desktop: 0
|
||||||
|
supported: 0, 1
|
56
tests/fixtures/generic/simple_xrandr.json
vendored
Normal file
56
tests/fixtures/generic/simple_xrandr.json
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"screens": [
|
||||||
|
{
|
||||||
|
"screen_number": 0,
|
||||||
|
"minimum_width": 8,
|
||||||
|
"minimum_height": 8,
|
||||||
|
"current_width": 1920,
|
||||||
|
"current_height": 1080,
|
||||||
|
"maximum_width": 32767,
|
||||||
|
"maximum_height": 32767,
|
||||||
|
"associated_device": {
|
||||||
|
"associated_modes": [
|
||||||
|
{
|
||||||
|
"resolution_width": 1920,
|
||||||
|
"resolution_height": 1080,
|
||||||
|
"is_high_resolution": false,
|
||||||
|
"frequencies": [
|
||||||
|
{
|
||||||
|
"frequency": 60.03,
|
||||||
|
"is_current": true,
|
||||||
|
"is_preferred": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frequency": 59.93,
|
||||||
|
"is_current": false,
|
||||||
|
"is_preferred": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resolution_width": 1680,
|
||||||
|
"resolution_height": 1050,
|
||||||
|
"is_high_resolution": false,
|
||||||
|
"frequencies": [
|
||||||
|
{
|
||||||
|
"frequency": 59.88,
|
||||||
|
"is_current": false,
|
||||||
|
"is_preferred": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"is_connected": true,
|
||||||
|
"is_primary": true,
|
||||||
|
"device_name": "eDP1",
|
||||||
|
"resolution_width": 1920,
|
||||||
|
"resolution_height": 1080,
|
||||||
|
"offset_width": 0,
|
||||||
|
"offset_height": 0,
|
||||||
|
"dimension_width": 310,
|
||||||
|
"dimension_height": 170
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unassociated_devices": []
|
||||||
|
}
|
4
tests/fixtures/generic/simple_xrandr.out
vendored
Normal file
4
tests/fixtures/generic/simple_xrandr.out
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
|
||||||
|
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm
|
||||||
|
1920x1080 60.03*+ 59.93
|
||||||
|
1680x1050 59.88
|
38
tests/fixtures/generic/xrandr.out
vendored
Normal file
38
tests/fixtures/generic/xrandr.out
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
|
||||||
|
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm
|
||||||
|
1920x1080 60.03*+ 59.93
|
||||||
|
1680x1050 59.88
|
||||||
|
1400x1050 59.98
|
||||||
|
1600x900 60.00 59.95 59.82
|
||||||
|
1280x1024 60.02
|
||||||
|
1400x900 59.96 59.88
|
||||||
|
1280x960 60.00
|
||||||
|
1368x768 60.00 59.88 59.85
|
||||||
|
1280x800 59.81 59.91
|
||||||
|
1280x720 59.86 60.00 59.74
|
||||||
|
1024x768 60.00
|
||||||
|
1024x576 60.00 59.90 59.82
|
||||||
|
960x540 60.00 59.63 59.82
|
||||||
|
800x600 60.32 56.25
|
||||||
|
864x486 60.00 59.92 59.57
|
||||||
|
640x480 59.94
|
||||||
|
720x405 59.51 60.00 58.99
|
||||||
|
640x360 59.84 59.32 60.00
|
||||||
|
DP1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
DP2 disconnected (normal left inverted right x axis y axis)
|
||||||
|
HDMI1 connected (normal left inverted right x axis y axis)
|
||||||
|
1920x1080 60.00 + 50.00 59.94
|
||||||
|
1920x1080i 60.00 50.00 59.94
|
||||||
|
1680x1050 59.88
|
||||||
|
1280x1024 75.02 60.02
|
||||||
|
1440x900 59.90
|
||||||
|
1280x960 60.00
|
||||||
|
1280x720 60.00 50.00 59.94
|
||||||
|
1024x768 75.03 70.07 60.00
|
||||||
|
832x624 74.55
|
||||||
|
800x600 72.19 75.00 60.32 56.25
|
||||||
|
720x576 50.00
|
||||||
|
720x480 60.00 59.94
|
||||||
|
640x480 75.00 72.81 66.67 60.00 59.94
|
||||||
|
720x400 70.08
|
||||||
|
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
|
43
tests/fixtures/generic/xrandr_2.out
vendored
Normal file
43
tests/fixtures/generic/xrandr_2.out
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384
|
||||||
|
eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 174mm
|
||||||
|
1920x1080 60.03*+ 60.01 59.97 59.96 59.93
|
||||||
|
1680x1050 59.95 59.88
|
||||||
|
1400x1050 59.98
|
||||||
|
1600x900 59.99 59.94 59.95 59.82
|
||||||
|
1280x1024 60.02
|
||||||
|
1400x900 59.96 59.88
|
||||||
|
1280x960 60.00
|
||||||
|
1440x810 60.00 59.97
|
||||||
|
1368x768 59.88 59.85
|
||||||
|
1280x800 59.99 59.97 59.81 59.91
|
||||||
|
1280x720 60.00 59.99 59.86 59.74
|
||||||
|
1024x768 60.04 60.00
|
||||||
|
960x720 60.00
|
||||||
|
928x696 60.05
|
||||||
|
896x672 60.01
|
||||||
|
1024x576 59.95 59.96 59.90 59.82
|
||||||
|
960x600 59.93 60.00
|
||||||
|
960x540 59.96 59.99 59.63 59.82
|
||||||
|
800x600 60.00 60.32 56.25
|
||||||
|
840x525 60.01 59.88
|
||||||
|
864x486 59.92 59.57
|
||||||
|
700x525 59.98
|
||||||
|
800x450 59.95 59.82
|
||||||
|
640x512 60.02
|
||||||
|
700x450 59.96 59.88
|
||||||
|
640x480 60.00 59.94
|
||||||
|
720x405 59.51 58.99
|
||||||
|
684x384 59.88 59.85
|
||||||
|
640x400 59.88 59.98
|
||||||
|
640x360 59.86 59.83 59.84 59.32
|
||||||
|
512x384 60.00
|
||||||
|
512x288 60.00 59.92
|
||||||
|
480x270 59.63 59.82
|
||||||
|
400x300 60.32 56.34
|
||||||
|
432x243 59.92 59.57
|
||||||
|
320x240 60.05
|
||||||
|
360x202 59.51 59.13
|
||||||
|
320x180 59.84 59.32
|
||||||
|
DP-1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
HDMI-1 disconnected (normal left inverted right x axis y axis)
|
||||||
|
DP-2 disconnected (normal left inverted right x axis y axis)
|
15
tests/fixtures/generic/xrandr_device.out
vendored
Normal file
15
tests/fixtures/generic/xrandr_device.out
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
HDMI1 connected (normal left inverted right x axis y axis)
|
||||||
|
1920x1080 60.00 + 50.00 59.94
|
||||||
|
1920x1080i 60.00 50.00 59.94
|
||||||
|
1680x1050 59.88
|
||||||
|
1280x1024 75.02 60.02
|
||||||
|
1440x900 59.90
|
||||||
|
1280x960 60.00
|
||||||
|
1280x720 60.00 50.00 59.94
|
||||||
|
1024x768 75.03 70.07 60.00
|
||||||
|
832x624 74.55
|
||||||
|
800x600 72.19 75.00 60.32 56.25
|
||||||
|
720x576 50.00
|
||||||
|
720x480 60.00 59.94
|
||||||
|
640x480 75.00 72.81 66.67 60.00 59.94
|
||||||
|
720x400 70.08
|
172
tests/test_xrandr.py
Normal file
172
tests/test_xrandr.py
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import json
|
||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from jc.parsers.xrandr import (
|
||||||
|
_parse_screen,
|
||||||
|
_parse_device,
|
||||||
|
_parse_mode,
|
||||||
|
_device_pattern,
|
||||||
|
_screen_pattern,
|
||||||
|
_mode_pattern,
|
||||||
|
_frequencies_pattern,
|
||||||
|
parse,
|
||||||
|
Mode,
|
||||||
|
Device,
|
||||||
|
Screen,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class XrandrTests(unittest.TestCase):
|
||||||
|
def test_regexes(self):
|
||||||
|
devices = [
|
||||||
|
"HDMI1 connected (normal left inverted right x axis y axis)",
|
||||||
|
"VIRTUAL1 disconnected (normal left inverted right x axis y axis)",
|
||||||
|
"eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm",
|
||||||
|
"eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 174mm"
|
||||||
|
]
|
||||||
|
for device in devices:
|
||||||
|
self.assertIsNotNone(re.match(_device_pattern, device))
|
||||||
|
|
||||||
|
screens = [
|
||||||
|
"Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767",
|
||||||
|
"Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384"
|
||||||
|
]
|
||||||
|
for screen in screens:
|
||||||
|
self.assertIsNotNone(re.match(_screen_pattern, screen))
|
||||||
|
|
||||||
|
modes = [
|
||||||
|
"1920x1080 60.03*+ 59.93",
|
||||||
|
"1680x1050 59.88",
|
||||||
|
"1400x1050 59.98",
|
||||||
|
"1600x900 60.00 59.95 59.82",
|
||||||
|
"1280x1024 60.02",
|
||||||
|
"1400x900 59.96 59.88",
|
||||||
|
]
|
||||||
|
for mode in modes:
|
||||||
|
match = re.match(_mode_pattern, mode)
|
||||||
|
self.assertIsNotNone(match)
|
||||||
|
if match:
|
||||||
|
rest = match.groupdict()["rest"]
|
||||||
|
self.assertIsNotNone(re.match(_frequencies_pattern, rest))
|
||||||
|
|
||||||
|
def test_screens(self):
|
||||||
|
sample = "Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767"
|
||||||
|
|
||||||
|
actual: Optional[Screen] = _parse_screen([sample])
|
||||||
|
self.assertIsNotNone(actual)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"screen_number": 0,
|
||||||
|
"minimum_width": 8,
|
||||||
|
"minimum_height": 8,
|
||||||
|
"current_width": 1920,
|
||||||
|
"current_height": 1080,
|
||||||
|
"maximum_width": 32767,
|
||||||
|
"maximum_height": 32767,
|
||||||
|
}
|
||||||
|
if actual:
|
||||||
|
for k, v in expected.items():
|
||||||
|
self.assertEqual(v, actual[k], f"screens regex failed on {k}")
|
||||||
|
|
||||||
|
sample = "Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384"
|
||||||
|
actual = _parse_screen([sample])
|
||||||
|
if actual:
|
||||||
|
self.assertEqual(320, actual["minimum_width"])
|
||||||
|
else:
|
||||||
|
raise AssertionError("Screen should not be None")
|
||||||
|
|
||||||
|
def test_device(self):
|
||||||
|
# regex101 sample link for tests/edits https://regex101.com/r/3cHMv3/1
|
||||||
|
sample = "eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm"
|
||||||
|
actual: Optional[Device] = _parse_device([sample])
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"device_name": "eDP1",
|
||||||
|
"is_connected": True,
|
||||||
|
"is_primary": True,
|
||||||
|
"resolution_width": 1920,
|
||||||
|
"resolution_height": 1080,
|
||||||
|
"offset_width": 0,
|
||||||
|
"offset_height": 0,
|
||||||
|
"dimension_width": 310,
|
||||||
|
"dimension_height": 170,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertIsNotNone(actual)
|
||||||
|
|
||||||
|
if actual:
|
||||||
|
for k, v in expected.items():
|
||||||
|
self.assertEqual(v, actual[k], f"Devices regex failed on {k}")
|
||||||
|
|
||||||
|
with open("tests/fixtures/generic/xrandr_device.out", "r") as f:
|
||||||
|
extended_sample = f.read().splitlines()
|
||||||
|
extended_sample.reverse()
|
||||||
|
|
||||||
|
device = _parse_device(extended_sample)
|
||||||
|
if device:
|
||||||
|
self.assertEqual(
|
||||||
|
59.94, device["associated_modes"][12]["frequencies"][4]["frequency"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_mode(self):
|
||||||
|
sample_1 = "1920x1080 60.03*+ 59.93"
|
||||||
|
expected = {
|
||||||
|
"frequencies": [
|
||||||
|
{"frequency": 60.03, "is_current": True, "is_preferred": True},
|
||||||
|
{"frequency": 59.93, "is_current": False, "is_preferred": False},
|
||||||
|
],
|
||||||
|
"resolution_width": 1920,
|
||||||
|
"resolution_height": 1080,
|
||||||
|
"is_high_resolution": False,
|
||||||
|
}
|
||||||
|
actual: Optional[Mode] = _parse_mode(sample_1)
|
||||||
|
|
||||||
|
self.assertIsNotNone(actual)
|
||||||
|
|
||||||
|
if actual:
|
||||||
|
for k, v in expected.items():
|
||||||
|
self.assertEqual(v, actual[k], f"mode regex failed on {k}")
|
||||||
|
|
||||||
|
sample_2 = " 1920x1080i 60.00 50.00 59.94"
|
||||||
|
actual: Optional[Mode] = _parse_mode(sample_2)
|
||||||
|
self.assertIsNotNone(actual)
|
||||||
|
if actual:
|
||||||
|
self.assertEqual(True, actual["is_high_resolution"])
|
||||||
|
self.assertEqual(50.0, actual["frequencies"][1]["frequency"])
|
||||||
|
|
||||||
|
def test_complete(self):
|
||||||
|
self.maxDiff = None
|
||||||
|
with open("tests/fixtures/generic/xrandr.out", "r") as f:
|
||||||
|
txt = f.read()
|
||||||
|
actual = parse(txt)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(actual["screens"]))
|
||||||
|
self.assertEqual(4, len(actual["unassociated_devices"]))
|
||||||
|
self.assertEqual(
|
||||||
|
18, len(actual["screens"][0]["associated_device"]["associated_modes"])
|
||||||
|
)
|
||||||
|
|
||||||
|
with open("tests/fixtures/generic/xrandr_2.out", "r") as f:
|
||||||
|
txt = f.read()
|
||||||
|
actual = parse(txt)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(actual["screens"]))
|
||||||
|
self.assertEqual(3, len(actual["unassociated_devices"]))
|
||||||
|
self.assertEqual(
|
||||||
|
38, len(actual["screens"][0]["associated_device"]["associated_modes"])
|
||||||
|
)
|
||||||
|
|
||||||
|
with open("tests/fixtures/generic/simple_xrandr.out", "r") as f:
|
||||||
|
txt = f.read()
|
||||||
|
actual = parse(txt)
|
||||||
|
|
||||||
|
with open("tests/fixtures/generic/simple_xrandr.json", "w") as f:
|
||||||
|
json.dump(actual, f, indent=True)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(actual["screens"]))
|
||||||
|
self.assertEqual(0, len(actual["unassociated_devices"]))
|
||||||
|
self.assertEqual(
|
||||||
|
2, len(actual["screens"][0]["associated_device"]["associated_modes"])
|
||||||
|
)
|
Reference in New Issue
Block a user