1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-07-17 01:32:37 +02:00

Merge pull request #655 from kellyjonbrazil/dev

Dev v1.25.5
This commit is contained in:
Kelly Brazil
2025-05-10 11:38:04 -07:00
committed by GitHub
49 changed files with 820 additions and 225 deletions

View File

@ -9,13 +9,41 @@ on:
- "**/*.py"
jobs:
very_old_python:
if: github.event.pull_request.draft == false
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-13, windows-2019]
python-version: ["3.6"]
steps:
- uses: actions/checkout@v3
- name: "Set up timezone to America/Los_Angeles"
uses: szenius/set-timezone@v1.2
with:
timezoneLinux: "America/Los_Angeles"
timezoneMacos: "America/Los_Angeles"
timezoneWindows: "Pacific Standard Time"
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Test with unittest
run: |
python -m unittest discover tests
old_python:
if: github.event.pull_request.draft == false
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-13, ubuntu-20.04, windows-2019]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
os: [macos-13, ubuntu-22.04, windows-2019]
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3

View File

@ -1,5 +1,17 @@
jc changelog
20250503 v1.25.5
- Add `amixer` command parser
- Enhance `iptables` command parser to add default policy statistics fields
- Fix `bluetoothctl` parser failing to parse controllers with power state prop
- Fix `lsblk` command parser to support multiple mountpoints. Also, added
byte conversions for size fields.
- Fix `nmcli` command parser to support `team.config` JSON field
- Fix `time` command parser for output that does not contain centiseconds
- Fix `x509-cert` parser to handle IDNA2008 encoded email addresses with a warning
- Fix typing for upcoming python v3.14
- Fix timezone setting for tests to support minimal chrooted builds
20241125 v1.25.4
- Add `ipconfig` command parser (`ipconfig` for Windows)
- Add `pacman` command parser

View File

@ -159,6 +159,7 @@ option.
| `--acpi` | `acpi` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/acpi) |
| `--airport` | `airport -I` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/airport) |
| `--airport-s` | `airport -s` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/airport_s) |
| `--amixer` | `amixer` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/amixer) |
| `--apt-cache-show` | `apt-cache show` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/apt_cache_show) |
| `--apt-get-sqq` | `apt-get -sqq` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/apt_get_sqq) |
| `--arp` | `arp` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/arp) |
@ -1378,4 +1379,4 @@ cat istio.yaml | jc -p --yaml
]
```
© 2019-2024 Kelly Brazil
© 2019-2025 Kelly Brazil

View File

@ -3,8 +3,8 @@ _jc()
local cur prev words cword jc_commands jc_parsers jc_options \
jc_about_options jc_about_mod_options jc_help_options jc_special_options
jc_commands=(acpi airport apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr zipinfo zpool)
jc_parsers=(--acpi --airport --airport-s --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-tcp --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --resolve-conf --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
jc_commands=(acpi airport amixer apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr zipinfo zpool)
jc_parsers=(--acpi --airport --airport-s --amixer --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-tcp --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --resolve-conf --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
jc_options=(--force-color -C --debug -d --monochrome -m --meta-out -M --pretty -p --quiet -q --raw -r --slurp -s --unbuffer -u --yaml-out -y)
jc_about_options=(--about -a)
jc_about_mod_options=(--pretty -p --yaml-out -y --monochrome -m --force-color -C)

View File

@ -9,10 +9,11 @@ _jc() {
jc_help_options jc_help_options_describe \
jc_special_options jc_special_options_describe
jc_commands=(acpi airport apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr zipinfo zpool)
jc_commands=(acpi airport amixer apt-cache apt-get arp blkid bluetoothctl cbt certbot chage cksum crontab curl date debconf-show df dig dmidecode dpkg du efibootmgr env ethtool file findmnt finger free git gpg hciconfig host id ifconfig iostat ip ipconfig iptables iw iwconfig jobs last lastb ls lsattr lsb_release lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat needrestart netstat nmcli nsd-control ntpq os-prober pacman pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss ssh sshd stat sum swapon sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 tune2fs udevadm ufw uname update-alternatives upower uptime vdir veracrypt vmstat w wc wg who xrandr zipinfo zpool)
jc_commands_describe=(
'acpi:run "acpi" command with magic syntax.'
'airport:run "airport" command with magic syntax.'
'amixer:run "amixer" command with magic syntax.'
'apt-cache:run "apt-cache" command with magic syntax.'
'apt-get:run "apt-get" command with magic syntax.'
'arp:run "arp" command with magic syntax.'
@ -124,11 +125,12 @@ _jc() {
'zipinfo:run "zipinfo" command with magic syntax.'
'zpool:run "zpool" command with magic syntax.'
)
jc_parsers=(--acpi --airport --airport-s --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-tcp --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --resolve-conf --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
jc_parsers=(--acpi --airport --airport-s --amixer --apt-cache-show --apt-get-sqq --arp --asciitable --asciitable-m --blkid --bluetoothctl --cbt --cef --cef-s --certbot --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --curl-head --date --datetime-iso --debconf-show --df --dig --dir --dmidecode --dpkg-l --du --efibootmgr --email-address --env --ethtool --file --find --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --host --hosts --http-headers --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --ipconfig --iptables --ip-route --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --kv-dup --last --ls --ls-s --lsattr --lsb-release --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --needrestart --netstat --nmcli --nsd-control --ntpq --openvpn --os-prober --os-release --pacman --passwd --path --path-list --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --pkg-index-apk --pkg-index-deb --plist --postconf --proc --proc-buddyinfo --proc-cmdline --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-tcp --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --resolve-conf --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --srt --ss --ssh-conf --sshd-conf --stat --stat-s --swapon --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --tune2fs --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --ver --veracrypt --vmstat --vmstat-s --w --wc --wg-show --who --x509-cert --x509-csr --xml --xrandr --yaml --zipinfo --zpool-iostat --zpool-status)
jc_parsers_describe=(
'--acpi:`acpi` command parser'
'--airport:`airport -I` command parser'
'--airport-s:`airport -s` command parser'
'--amixer:`amixer` command parser'
'--apt-cache-show:`apt-cache show` command parser'
'--apt-get-sqq:`apt-get -sqq` command parser'
'--arp:`arp` command parser'

117
docs/parsers/amixer.md Normal file
View File

@ -0,0 +1,117 @@
[Home](https://kellyjonbrazil.github.io/jc/)
<a id="jc.parsers.amixer"></a>
# jc.parsers.amixer
jc - JSON Convert `amixer sget` command output parser
Usage (cli):
$ amixer sget <control_name> | jc --amixer
$ amixer sget Master | jc --amixer
$ amixer sget Capture | jc --amixer
$ amixer sget Speakers | jc --amixer
Usage (module):
import jc
result = jc.parse('amixer', <amixer_sget_command_output>)
Schema:
{
"control_name": string,
"capabilities": [
string
],
"playback_channels": [
string
],
"limits": {
"playback_min": integer,
"playback_max": integer
},
"mono": {
"playback_value": integer,
"percentage": integer,
"db": float,
"status": boolean
}
}
Examples:
$ amixer sget Master | jc --amixer -p
{
"control_name": "Capture",
"capabilities": [
"cvolume",
"cswitch"
],
"playback_channels": [],
"limits": {
"playback_min": 0,
"playback_max": 63
},
"front_left": {
"playback_value": 63,
"percentage": 100,
"db": 30.0,
"status": true
},
"front_right": {
"playback_value": 63,
"percentage": 100,
"db": 30.0,
"status": true
}
}
$ amixer sget Master | jc --amixer -p -r
{
"control_name": "Master",
"capabilities": [
"pvolume",
"pvolume-joined",
"pswitch",
"pswitch-joined"
],
"playback_channels": [
"Mono"
],
"limits": {
"playback_min": "0",
"playback_max": "87"
},
"mono": {
"playback_value": "87",
"percentage": "100%",
"db": "0.00db",
"status": "on"
}
}
<a id="jc.parsers.amixer.parse"></a>
### parse
```python
def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict
```
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True
Returns:
Dictionary. Raw or processed structured data.
### Parser Information
Compatibility: linux
Source: [`jc/parsers/amixer.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/amixer.py)
Version 1.0 by Eden Refael (edenraf@hotmail.com)

View File

@ -136,4 +136,4 @@ Compatibility: linux
Source: [`jc/parsers/bluetoothctl.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/bluetoothctl.py)
Version 1.3 by Jake Ob (iakopap at gmail.com)
Version 1.4 by Jake Ob (iakopap at gmail.com)

View File

@ -25,6 +25,9 @@ Schema:
[
{
"chain": string,
"default_policy": string,
"default_packets": integer,
"default_bytes": integer,
"rules": [
{
"num" integer,
@ -49,6 +52,9 @@ Examples:
[
{
"chain": "PREROUTING",
"default_policy": "DROP",
"default_packets": 0,
"default_bytes": 0,
"rules": [
{
"num": 1,
@ -108,6 +114,9 @@ Examples:
[
{
"chain": "PREROUTING",
"default_policy": "DROP",
"default_packets": "0",
"default_bytes": "0",
"rules": [
{
"num": "1",
@ -188,4 +197,4 @@ Compatibility: linux
Source: [`jc/parsers/iptables.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/iptables.py)
Version 1.11 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.12 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -22,46 +22,53 @@ Schema:
[
{
"name": string,
"maj_min": string,
"rm": boolean,
"size": string,
"ro": boolean,
"type": string,
"mountpoint": string,
"kname": string,
"fstype": string,
"label": string,
"uuid": string,
"partlabel": string,
"partuuid": string,
"ra": integer,
"model": string,
"serial": string,
"state": string,
"owner": string,
"group": string,
"mode": string,
"alignment": integer,
"min_io": integer,
"opt_io": integer,
"phy_sec": integer,
"log_sec": integer,
"rota": boolean,
"sched": string,
"rq_size": integer,
"disc_aln": integer,
"disc_gran": string,
"disc_max": string,
"disc_zero": boolean,
"wsame": string,
"wwn": string,
"rand": boolean,
"pkname": string,
"hctl": string,
"tran": string,
"rev": string,
"vendor": string
"name": string,
"maj_min": string,
"rm": boolean,
"size": string,
"size_bytes": integer
"ro": boolean,
"type": string,
"mountpoint": string,
"mountpoints": [
string
],
"kname": string,
"fstype": string,
"label": string,
"uuid": string,
"partlabel": string,
"partuuid": string,
"ra": integer,
"model": string,
"serial": string,
"state": string,
"owner": string,
"group": string,
"mode": string,
"alignment": integer,
"min_io": integer,
"opt_io": integer,
"phy_sec": integer,
"log_sec": integer,
"rota": boolean,
"sched": string,
"rq_size": integer,
"disc_aln": integer,
"disc_gran": string,
"disc_gran_bytes": integer,
"disc_max": string,
"disc_max_bytes": integer,
"disc_zero": boolean,
"wsame": string,
"wsame_bytes": integer,
"wwn": string,
"rand": boolean,
"pkname": string,
"hctl": string,
"tran": string,
"rev": string,
"vendor": string
}
]
@ -74,6 +81,7 @@ Examples:
"maj_min": "8:0",
"rm": false,
"size": "20G",
"size_bytes": 20000000000,
"ro": false,
"type": "disk",
"mountpoint": null
@ -83,6 +91,7 @@ Examples:
"maj_min": "8:1",
"rm": false,
"size": "1G",
"size_bytes": 1000000000
"ro": false,
"type": "part",
"mountpoint": "/boot"
@ -100,6 +109,7 @@ Examples:
"maj_min": "8:0",
"rm": false,
"size": "20G",
"size_bytes": 20000000000,
"ro": false,
"type": "disk",
"mountpoint": null,
@ -126,9 +136,12 @@ Examples:
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": false,
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": true,
"pkname": null,
@ -142,6 +155,7 @@ Examples:
"maj_min": "8:1",
"rm": false,
"size": "1G",
"size_bytes": 1000000000
"ro": false,
"type": "part",
"mountpoint": "/boot",
@ -168,9 +182,12 @@ Examples:
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": false,
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": true,
"pkname": "sda",
@ -192,6 +209,7 @@ Examples:
"maj_min": "8:0",
"rm": "0",
"size": "20G",
"size_bytes": 20000000000,
"ro": "0",
"type": "disk",
"mountpoint": null,
@ -218,9 +236,12 @@ Examples:
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": "0",
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": "1",
"pkname": null,
@ -234,6 +255,7 @@ Examples:
"maj_min": "8:1",
"rm": "0",
"size": "1G",
"size_bytes": 1000000000
"ro": "0",
"type": "part",
"mountpoint": "/boot",
@ -260,9 +282,12 @@ Examples:
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": "0",
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": "1",
"pkname": "sda",
@ -299,4 +324,4 @@ Compatibility: linux
Source: [`jc/parsers/lsblk.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/lsblk.py)
Version 1.9 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.10 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -100,4 +100,4 @@ Compatibility: linux, darwin, freebsd, aix
Source: [`jc/parsers/mount.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/mount.py)
Version 1.10 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.11 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -41,6 +41,7 @@ These are documented below.
[
{
"<key>": string/integer/float, # [0]
"team_config": object,
"dhcp4_option_x": {
"name": string,
"value": string/integer/float,
@ -170,4 +171,4 @@ Compatibility: linux
Source: [`jc/parsers/nmcli.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/nmcli.py)
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -157,4 +157,4 @@ Compatibility: linux, darwin, cygwin, aix, freebsd
Source: [`jc/parsers/time.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/time.py)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -435,4 +435,4 @@ Compatibility: linux, darwin, cygwin, win32, aix, freebsd
Source: [`jc/parsers/x509_cert.py`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/x509_cert.py)
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -52,7 +52,7 @@ class info():
author: str = 'Kelly Brazil'
author_email: str = 'kellyjonbrazil@gmail.com'
website: str = 'https://github.com/kellyjonbrazil/jc'
copyright: str = '© 2019-2024 Kelly Brazil'
copyright: str = '© 2019-2025 Kelly Brazil'
license: str = 'MIT License'

View File

@ -10,7 +10,7 @@ from jc import appdirs
from jc import utils
__version__ = '1.25.4'
__version__ = '1.25.5'
parsers: List[str] = [
'acpi',

View File

@ -10,7 +10,7 @@ Usage (cli):
Usage (module):
import jc
result = jc.parse('amixer', <amixer sget command output>)
result = jc.parse('amixer', <amixer_sget_command_output>)
Schema:
@ -20,7 +20,7 @@ Schema:
string
],
"playback_channels": [
string
string
],
"limits": {
"playback_min": integer,
@ -85,13 +85,12 @@ Examples:
"status": "on"
}
}
"""
from typing import List, Dict
from typing import Dict
import jc.utils
from jc.utils import convert_to_int
from jc.exceptions import ParseError
class info():
"""Provides parser metadata (version, author, etc.)"""
@ -107,7 +106,7 @@ class info():
__version__ = info.version
def _process(proc_data: dict) -> dict:
def _process(proc_data: Dict) -> Dict:
"""
Processes raw structured data to match the schema requirements.
@ -117,6 +116,9 @@ def _process(proc_data: dict) -> dict:
Returns:
(dict) processed structured data adhering to the schema
"""
if not proc_data:
return {}
# Initialize the processed dictionary
processed = {
"control_name": proc_data.get("control_name", ""),
@ -147,20 +149,17 @@ def parse(
data: str,
raw: bool = False,
quiet: bool = False
) -> List[Dict]:
) -> Dict:
"""
Main text parsing function, The amixer is alsa mixer tool and output, Will work with Linux OS only.
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True
Returns:
List of Dictionaries. Raw or processed structured data.
push test
Dictionary. Raw or processed structured data.
"""
"""
The Algorithm for parsing the `amixer sget` command, Input Explained/Rules/Pseudo Algorithm:
@ -172,7 +171,6 @@ def parse(
3b. Playback channels - List of channels
4. Limits - We'll always have the minimum limit and the maximum limit.
Input Example:
1."":~$ amixer sget Capture
Simple mixer control 'Capture',0
@ -182,9 +180,6 @@ def parse(
Front Left: Capture 63 [100%] [30.00db] [on]
Front Right: Capture 63 [100%] [30.00db] [on]
2."":~$ amixer sget Master
Simple mixer control 'Master',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
@ -192,10 +187,6 @@ def parse(
Limits: Playback 0 - 87
Mono: Playback 87 [100%] [0.00db] [on]
3."":~$ amixer sget Speaker
Simple mixer control 'Speaker',0
Capabilities: pvolume pswitch
@ -205,9 +196,6 @@ def parse(
Front Left: Playback 87 [100%] [0.00db] [on]
Front Right: Playback 87 [100%] [0.00db] [on]
4."":~$ amixer sget Headphone
Simple mixer control 'Headphone',0
Capabilities: pvolume pswitch
@ -224,54 +212,62 @@ def parse(
jc.utils.input_type_check(data)
# starts the parsing from here
mapping = {}
# split lines and than work on each line
lines = data.splitlines()
first_line = lines[0].strip()
mapping: Dict = {}
# Extract the control name from the first line
if first_line.startswith("Simple mixer control"):
control_name = first_line.split("'")[1]
else:
raise ValueError("Invalid amixer output format: missing control name.")
# map the control name
mapping["control_name"] = control_name
if jc.utils.has_data(data):
# split lines and than work on each line
lines = data.splitlines()
first_line = lines[0].strip()
# Process subsequent lines for capabilities, channels, limits, and channel-specific mapping.
# gets the lines from the next line - because we already took care the first line.
for line in lines[1:]:
# strip the line (maybe there are white spaces in the begin&end)
line = line.strip()
# Extract the control name from the first line
if first_line.startswith("Simple mixer control"):
control_name = first_line.split("'")[1]
else:
raise ParseError("Invalid amixer output format: missing control name.")
# map the control name
mapping["control_name"] = control_name
if line.startswith("Capabilities:"):
mapping["capabilities"] = line.split(":")[1].strip().split()
elif line.startswith("Playback channels:"):
mapping["playback_channels"] = line.split(":")[1].strip().split(" - ")
elif line.startswith("Limits:"):
limits = line.split(":")[1].strip().split(" - ")
mapping["limits"] = {
"playback_min": limits[0].split()[1],
"playback_max": limits[1]
}
elif line.startswith("Mono:") or line.startswith("Front Left:") or line.startswith("Front Right:"):
# Identify the channel name and parse its information
channel_name = line.split(":")[0].strip().lower().replace(" ", "_")
channel_info = line.split(":")[1].strip()
# Example: "Playback 255 [100%] [0.00db] [on]"
channel_data = channel_info.split(" ")
if channel_data[0] == "":
continue
playback_value = channel_data[1]
percentage = channel_data[2].strip("[]") # Extract percentage e.g., "100%"
db_value = channel_data[3].strip("[]") # Extract db value e.g., "0.00db"
status = channel_data[4].strip("[]") # Extract status e.g., "on" or "off"
# Process subsequent lines for capabilities, channels, limits, and channel-specific mapping.
# gets the lines from the next line - because we already took care the first line.
for line in lines[1:]:
# strip the line (maybe there are white spaces in the begin&end)
line = line.strip()
# Store channel mapping in the dictionary
mapping[channel_name] = {
"playback_value": playback_value,
"percentage": percentage,
"db": db_value.lower(),
"status": status
}
if line.startswith("Capabilities:"):
mapping["capabilities"] = line.split(":")[1].strip().split()
elif line.startswith("Playback channels:"):
mapping["playback_channels"] = line.split(":")[1].strip().split(" - ")
elif line.startswith("Limits:"):
limits = line.split(":")[1].strip().split(" - ")
mapping["limits"] = {
"playback_min": limits[0].split()[1],
"playback_max": limits[1]
}
elif line.startswith("Mono:") or line.startswith("Front Left:") or line.startswith("Front Right:"):
# Identify the channel name and parse its information
channel_name = line.split(":")[0].strip().lower().replace(" ", "_")
channel_info = line.split(":")[1].strip()
# Example: "Playback 255 [100%] [0.00db] [on]"
channel_data = channel_info.split(" ")
if channel_data[0] == "":
continue
if "dB" in channel_data[3]:
db_value = channel_data[3].strip("[]")
status = channel_data[4].strip("[]")
else:
db_value = "0.0db"
status = channel_data[3].strip("[]")
playback_value = channel_data[1]
percentage = channel_data[2].strip("[]") # Extract percentage e.g., "100%"
# Store channel mapping in the dictionary
mapping[channel_name] = {
"playback_value": playback_value,
"percentage": percentage,
"db": db_value.lower(),
"status": status
}
return mapping if raw else _process(mapping)

View File

@ -255,7 +255,7 @@ class EmailAddress(IA5String):
# fix to allow incorrectly encoded email addresses to succeed with warning
try:
self._unicode = mailbox.decode('cp1252') + '@' + hostname.decode('idna')
except UnicodeDecodeError:
except (UnicodeDecodeError, UnicodeError):
ascii_mailbox = mailbox.decode('ascii', errors='backslashreplace')
ascii_hostname = hostname.decode('ascii', errors='backslashreplace')
from jc.utils import warning_message

View File

@ -112,7 +112,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = '`bluetoothctl` command parser'
author = 'Jake Ob'
author_email = 'iakopap at gmail.com'
@ -139,6 +139,7 @@ try:
"alias": str,
"class": str,
"powered": str,
"power_state": str,
"discoverable": str,
"discoverable_timeout": str,
"pairable": str,
@ -185,6 +186,7 @@ _controller_line_pattern = (
+ r"|\s*Alias:\s*(?P<alias>.+)"
+ r"|\s*Class:\s*(?P<class>.+)"
+ r"|\s*Powered:\s*(?P<powered>.+)"
+ r"|\s*PowerState:\s*(?P<power_state>.+)"
+ r"|\s*Discoverable:\s*(?P<discoverable>.+)"
+ r"|\s*DiscoverableTimeout:\s*(?P<discoverable_timeout>.+)"
+ r"|\s*Pairable:\s*(?P<pairable>.+)"
@ -219,6 +221,7 @@ def _parse_controller(next_lines: List[str]) -> Optional[Controller]:
"alias": '',
"class": '',
"powered": '',
"power_state": '',
"discoverable": '',
"discoverable_timeout": '',
"pairable": '',
@ -261,6 +264,8 @@ def _parse_controller(next_lines: List[str]) -> Optional[Controller]:
controller["class"] = matches["class"]
elif matches["powered"]:
controller["powered"] = matches["powered"]
elif matches["power_state"]:
controller["power_state"] = matches["power_state"]
elif matches["discoverable"]:
controller["discoverable"] = matches["discoverable"]
elif matches["discoverable_timeout"]:

View File

@ -20,6 +20,9 @@ Schema:
[
{
"chain": string,
"default_policy": string,
"default_packets": integer,
"default_bytes": integer,
"rules": [
{
"num" integer,
@ -44,6 +47,9 @@ Examples:
[
{
"chain": "PREROUTING",
"default_policy": "DROP",
"default_packets": 0,
"default_bytes": 0,
"rules": [
{
"num": 1,
@ -103,6 +109,9 @@ Examples:
[
{
"chain": "PREROUTING",
"default_policy": "DROP",
"default_packets": "0",
"default_bytes": "0",
"rules": [
{
"num": "1",
@ -158,12 +167,13 @@ Examples:
...
]
"""
import re
import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.11'
version = '1.12'
description = '`iptables` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -174,6 +184,17 @@ class info():
__version__ = info.version
chain_pkt_byt_pattern = re.compile(
r'''
\s\(policy\s
(?P<policy_name>.+)
\s
(?P<packets>.+)
\spackets,\s
(?P<bytes>.+)
\sbytes\)
''', re.VERBOSE
)
def _process(proc_data):
"""
@ -188,6 +209,13 @@ def _process(proc_data):
List of Dictionaries. Structured data to conform to the schema.
"""
for entry in proc_data:
if 'default_packets' in entry:
entry['default_packets'] = jc.utils.convert_to_int(entry['default_packets'])
if 'default_bytes' in entry:
entry['default_bytes'] = jc.utils.convert_size_to_int(entry['default_bytes'])
for rule in entry['rules']:
int_list = ['num', 'pkts']
for key in rule:
@ -243,6 +271,14 @@ def parse(data, raw=False, quiet=False):
parsed_line = line.split()
chain['chain'] = parsed_line[1]
stats_match = re.search(chain_pkt_byt_pattern, line)
if stats_match:
stats = stats_match.groupdict()
chain['default_policy'] = stats['policy_name']
chain['default_packets'] = stats['packets']
chain['default_bytes'] = stats['bytes']
chain['rules'] = []
continue

View File

@ -17,46 +17,53 @@ Schema:
[
{
"name": string,
"maj_min": string,
"rm": boolean,
"size": string,
"ro": boolean,
"type": string,
"mountpoint": string,
"kname": string,
"fstype": string,
"label": string,
"uuid": string,
"partlabel": string,
"partuuid": string,
"ra": integer,
"model": string,
"serial": string,
"state": string,
"owner": string,
"group": string,
"mode": string,
"alignment": integer,
"min_io": integer,
"opt_io": integer,
"phy_sec": integer,
"log_sec": integer,
"rota": boolean,
"sched": string,
"rq_size": integer,
"disc_aln": integer,
"disc_gran": string,
"disc_max": string,
"disc_zero": boolean,
"wsame": string,
"wwn": string,
"rand": boolean,
"pkname": string,
"hctl": string,
"tran": string,
"rev": string,
"vendor": string
"name": string,
"maj_min": string,
"rm": boolean,
"size": string,
"size_bytes": integer
"ro": boolean,
"type": string,
"mountpoint": string,
"mountpoints": [
string
],
"kname": string,
"fstype": string,
"label": string,
"uuid": string,
"partlabel": string,
"partuuid": string,
"ra": integer,
"model": string,
"serial": string,
"state": string,
"owner": string,
"group": string,
"mode": string,
"alignment": integer,
"min_io": integer,
"opt_io": integer,
"phy_sec": integer,
"log_sec": integer,
"rota": boolean,
"sched": string,
"rq_size": integer,
"disc_aln": integer,
"disc_gran": string,
"disc_gran_bytes": integer,
"disc_max": string,
"disc_max_bytes": integer,
"disc_zero": boolean,
"wsame": string,
"wsame_bytes": integer,
"wwn": string,
"rand": boolean,
"pkname": string,
"hctl": string,
"tran": string,
"rev": string,
"vendor": string
}
]
@ -69,6 +76,7 @@ Examples:
"maj_min": "8:0",
"rm": false,
"size": "20G",
"size_bytes": 20000000000,
"ro": false,
"type": "disk",
"mountpoint": null
@ -78,6 +86,7 @@ Examples:
"maj_min": "8:1",
"rm": false,
"size": "1G",
"size_bytes": 1000000000
"ro": false,
"type": "part",
"mountpoint": "/boot"
@ -95,6 +104,7 @@ Examples:
"maj_min": "8:0",
"rm": false,
"size": "20G",
"size_bytes": 20000000000,
"ro": false,
"type": "disk",
"mountpoint": null,
@ -121,9 +131,12 @@ Examples:
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": false,
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": true,
"pkname": null,
@ -137,6 +150,7 @@ Examples:
"maj_min": "8:1",
"rm": false,
"size": "1G",
"size_bytes": 1000000000
"ro": false,
"type": "part",
"mountpoint": "/boot",
@ -163,9 +177,12 @@ Examples:
"rq_size": 128,
"disc_aln": 0,
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": false,
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": true,
"pkname": "sda",
@ -187,6 +204,7 @@ Examples:
"maj_min": "8:0",
"rm": "0",
"size": "20G",
"size_bytes": 20000000000,
"ro": "0",
"type": "disk",
"mountpoint": null,
@ -213,9 +231,12 @@ Examples:
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": "0",
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": "1",
"pkname": null,
@ -229,6 +250,7 @@ Examples:
"maj_min": "8:1",
"rm": "0",
"size": "1G",
"size_bytes": 1000000000
"ro": "0",
"type": "part",
"mountpoint": "/boot",
@ -255,9 +277,12 @@ Examples:
"rq_size": "128",
"disc_aln": "0",
"disc_gran": "0B",
"disc_gran_bytes": 0,
"disc_max": "0B",
"disc_max_bytes": 0,
"disc_zero": "0",
"wsame": "32M",
"wsame_bytes": 32000000,
"wwn": null,
"rand": "1",
"pkname": "sda",
@ -275,7 +300,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.9'
version = '1.10'
description = '`lsblk` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -304,14 +329,19 @@ def _process(proc_data):
int_list = {'ra', 'alignment', 'min_io', 'opt_io', 'phy_sec', 'log_sec',
'rq_size', 'disc_aln'}
size_list = {'size', 'disc_gran', 'disc_max', 'wsame'}
for entry in proc_data:
for key in entry:
for key in entry.copy():
if key in bool_list:
entry[key] = jc.utils.convert_to_bool(entry[key])
if key in int_list:
entry[key] = jc.utils.convert_to_int(entry[key])
if key in size_list:
entry[key + '_bytes'] = jc.utils.convert_size_to_int(entry[key], posix_mode=True)
return proc_data
@ -335,6 +365,7 @@ def parse(data, raw=False, quiet=False):
# Clear any blank lines
cleandata = list(filter(None, data.splitlines()))
raw_output = []
new_list = []
if jc.utils.has_data(data):
@ -346,11 +377,23 @@ def parse(data, raw=False, quiet=False):
raw_output = jc.parsers.universal.sparse_table_parse(cleandata)
# clean up non-ascii characters, if any
# find multiple mount points and add to a single entry
for entry in raw_output:
entry['name'] = entry['name'].encode('ascii', errors='ignore').decode()
if entry['name']:
if 'mountpoints' in entry:
if entry['mountpoints']:
entry['mountpoints'] = [entry['mountpoints']]
else:
entry['mountpoints'] = []
new_list.append(entry)
elif 'mountpoints' in entry and entry['mountpoints']:
new_list[-1]['mountpoints'].append(entry['mountpoints'])
if raw:
return raw_output
else:
return _process(raw_output)
# clean up tree characters, if any
for entry in new_list:
tree_chars = ['`-', '|-', '├─', '└─']
for chars in tree_chars:
if entry['name'][0:2] == chars:
entry['name'] = entry['name'][2:]
return new_list if raw else _process(new_list)

View File

@ -71,13 +71,12 @@ Example:
]
"""
import re
import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.10'
version = '1.11'
description = '`mount` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -111,19 +110,24 @@ def _osx_parse(data):
for entry in data:
output_line = {}
filesystem = entry.split(' on ')
filesystem = filesystem[0]
output_line['filesystem'] = filesystem
pattern = re.compile(
r'''
(?P<filesystem>.*)
\son\s
(?P<mount_point>.*?)
\s
\((?P<options>.*?)\)\s*
''', re.VERBOSE
)
mount_point = entry.split(' on ')
mount_point = mount_point[1].split(' (')
mount_point = mount_point[0]
output_line['mount_point'] = mount_point
mymatch = pattern.match(entry)
groups = mymatch.groupdict()
options = entry.split('(', maxsplit=1)
options = options[1].rstrip(')')
options = options.split(', ')
output_line['options'] = options
if groups:
output_line['filesystem'] = groups['filesystem']
output_line['mount_point'] = groups['mount_point']
options = groups['options'].split(', ')
output_line['options'] = options
output.append(output_line)
@ -218,7 +222,7 @@ def parse(data, raw=False, quiet=False):
# check for OSX and AIX output
if ' type ' not in cleandata[0]:
if 'node' in cleandata[0]:
if ' node ' in cleandata[0]:
raw_output = _aix_parse(cleandata)
else:
raw_output = _osx_parse(cleandata)

View File

@ -36,6 +36,7 @@ These are documented below.
[
{
"<key>": string/integer/float, # [0]
"team_config": object,
"dhcp4_option_x": {
"name": string,
"value": string/integer/float,
@ -141,6 +142,7 @@ Examples:
]
"""
import re
import json
from typing import List, Dict, Optional
import jc.utils
from jc.parsers.universal import sparse_table_parse
@ -149,7 +151,7 @@ from jc.exceptions import ParseError
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.0'
version = '1.1'
description = '`nmcli` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -313,8 +315,30 @@ def _device_show_parse(data: str) -> List[Dict]:
def _connection_show_x_parse(data: str) -> List[Dict]:
raw_output: List = []
item: Dict = {}
in_team_config: bool = False
team_config_value: List = []
for line in filter(None, data.splitlines()):
# fix for team.config, which is multi-line JSON
if line.startswith('team.config:'):
in_team_config = True
_, value = line.split(':', maxsplit=1)
team_config_value.append(value.strip())
item['team_config'] = {}
continue
if not line.startswith('team.') and in_team_config:
team_config_value.append(line.strip())
continue
in_team_config = False
if team_config_value:
# team.config value should always be JSON
item['team_config'] = json.loads(''.join(team_config_value))
team_config_value = []
key, value = line.split(':', maxsplit=1)
key_n = _normalize_key(key)

View File

@ -4,7 +4,6 @@ Edid module
import struct
from collections import namedtuple
from typing import ByteString
__all__ = ["Edid"]
@ -108,10 +107,10 @@ class Edid:
),
)
def __init__(self, edid: ByteString):
def __init__(self, edid: bytes):
self._parse_edid(edid)
def _parse_edid(self, edid: ByteString):
def _parse_edid(self, edid: bytes):
"""Convert edid byte string to edid object"""
if struct.calcsize(self._STRUCT_FORMAT) != 128:
raise ValueError("Wrong edid size.")

View File

@ -3,7 +3,7 @@ EDID helper
"""
from subprocess import CalledProcessError, check_output
from typing import ByteString, List
from typing import List
__all__ = ["EdidHelper"]
@ -12,14 +12,14 @@ class EdidHelper:
"""Class for working with EDID data"""
@staticmethod
def hex2bytes(hex_data: str) -> ByteString:
def hex2bytes(hex_data: str) -> bytes:
"""Convert hex EDID string to bytes
Args:
hex_data (str): hex edid string
Returns:
ByteString: edid byte string
bytes: edid byte string
"""
# delete edid 1.3 additional block
if len(hex_data) > 256:
@ -32,14 +32,14 @@ class EdidHelper:
return bytes(numbers)
@classmethod
def get_edids(cls) -> List[ByteString]:
def get_edids(cls) -> List[bytes]:
"""Get edids from xrandr
Raises:
`RuntimeError`: if error with retrieving xrandr util data
Returns:
List[ByteString]: list with edids
List[bytes]: list with edids
"""
try:
output = check_output(["xrandr", "--verbose"])

View File

@ -132,7 +132,7 @@ import jc.utils
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.4'
version = '1.5'
description = '`/usr/bin/time` command parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'
@ -171,13 +171,18 @@ def _process(proc_data):
proc_data['command_being_timed'] = proc_data['command_being_timed'][1:-1]
if 'elapsed_time' in proc_data:
proc_data['elapsed_time'] = proc_data['elapsed_time'].replace('.', ':')
*hours, minutes, seconds, centiseconds = proc_data['elapsed_time'].split(':')
proc_data['elapsed_time'] = proc_data['elapsed_time'][::-1].replace(':', '.', 1)[::-1]
*hours, minutes, ss = proc_data['elapsed_time'].split(':')
if '.' in ss:
seconds, centiseconds = ss.split('.')
else:
seconds = ss
centiseconds = '0'
if hours:
proc_data['elapsed_time_hours'] = jc.utils.convert_to_int(hours[0])
else:
proc_data['elapsed_time_hours'] = 0
proc_data['elapsed_time_minutes'] = jc.utils.convert_to_int(minutes)
proc_data['elapsed_time_seconds'] = jc.utils.convert_to_int(seconds)
proc_data['elapsed_time_centiseconds'] = jc.utils.convert_to_int(centiseconds)

View File

@ -413,7 +413,7 @@ from jc.parsers.asn1crypto import pem, x509, jc_global
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.3'
version = '1.4'
description = 'X.509 PEM and DER certificate file parser'
author = 'Kelly Brazil'
author_email = 'kellyjonbrazil@gmail.com'

View File

@ -1,4 +1,4 @@
.TH jc 1 2024-11-25 1.25.4 "JSON Convert"
.TH jc 1 2025-05-10 1.25.5 "JSON Convert"
.SH NAME
\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types,
and strings
@ -52,6 +52,11 @@ Parsers:
\fB--airport-s\fP
`airport -s` command parser
.TP
.B
\fB--amixer\fP
`amixer` command parser
.TP
.B
\fB--apt-cache-show\fP
@ -1632,6 +1637,6 @@ Kelly Brazil (kellyjonbrazil@gmail.com)
https://github.com/kellyjonbrazil/jc
.SH COPYRIGHT
Copyright (c) 2019-2024 Kelly Brazil
Copyright (c) 2019-2025 Kelly Brazil
License: MIT License

View File

@ -1,5 +1,5 @@
#!/bin/bash
# system should be in "America/Los_Angeles" timezone for all tests to pass
# ensure no local plugin parsers are installed for all tests to pass
# system should be in "America/Los_Angeles" (PST8PDT) timezone for all tests
# to pass ensure no local plugin parsers are installed for all tests to pass
TZ=America/Los_Angeles python3 -m unittest -v
TZ=PST8PDT python3 -m unittest -v

View File

@ -5,7 +5,7 @@ with open('README.md', 'r') as f:
setuptools.setup(
name='jc',
version='1.25.4',
version='1.25.5',
author='Kelly Brazil',
author_email='kellyjonbrazil@gmail.com',
description='Converts the output of popular command-line tools and file-types to JSON.',

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
[{"name": "sda", "maj_min": "8:0", "rm": false, "size": "20G", "ro": false, "type": "disk", "mountpoint": null, "kname": "sda", "fstype": null, "label": null, "uuid": null, "partlabel": null, "partuuid": null, "ra": 4096, "model": "VMware Virtual S", "serial": null, "state": "running", "owner": "root", "group": "disk", "mode": "brw-rw----", "alignment": 0, "min_io": 512, "opt_io": 0, "phy_sec": 512, "log_sec": 512, "rota": true, "sched": "deadline", "rq_size": 128, "disc_aln": 0, "disc_gran": "0B", "disc_max": "0B", "disc_zero": false, "wsame": "32M", "wwn": null, "rand": true, "pkname": null, "hctl": "0:0:0:0", "tran": "spi", "rev": "1.0", "vendor": "VMware,"}, {"name": "sda1", "maj_min": "8:1", "rm": false, "size": "1G", "ro": false, "type": "part", "mountpoint": "/boot", "kname": "sda1", "fstype": "xfs", "label": null, "uuid": "05d927bb-5875-49e3-ada1-7f46cb31c932", "partlabel": null, "partuuid": null, "ra": 4096, "model": null, "serial": null, "state": null, "owner": "root", "group": "disk", "mode": "brw-rw----", "alignment": 0, "min_io": 512, "opt_io": 0, "phy_sec": 512, "log_sec": 512, "rota": true, "sched": "deadline", "rq_size": 128, "disc_aln": 0, "disc_gran": "0B", "disc_max": "0B", "disc_zero": false, "wsame": "32M", "wwn": null, "rand": true, "pkname": "sda", "hctl": null, "tran": null, "rev": null, "vendor": null}, {"name": "sda2", "maj_min": "8:2", "rm": false, "size": "19G", "ro": false, "type": "part", "mountpoint": null, "kname": "sda2", "fstype": "LVM2_member", "label": null, "uuid": "3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM", "partlabel": null, "partuuid": null, "ra": 4096, "model": null, "serial": null, "state": null, "owner": "root", "group": "disk", "mode": "brw-rw----", "alignment": 0, "min_io": 512, "opt_io": 0, "phy_sec": 512, "log_sec": 512, "rota": true, "sched": "deadline", "rq_size": 128, "disc_aln": 0, "disc_gran": "0B", "disc_max": "0B", "disc_zero": false, "wsame": "32M", "wwn": null, "rand": true, "pkname": "sda", "hctl": null, "tran": null, "rev": null, "vendor": null}, {"name": "centos-root", "maj_min": "253:0", "rm": false, "size": "17G", "ro": false, "type": "lvm", "mountpoint": "/", "kname": "dm-0", "fstype": "xfs", "label": null, "uuid": "07d718ef-950c-4e5b-98e0-42a1147b77d9", "partlabel": null, "partuuid": null, "ra": 4096, "model": null, "serial": null, "state": "running", "owner": "root", "group": "disk", "mode": "brw-rw----", "alignment": 0, "min_io": 512, "opt_io": 0, "phy_sec": 512, "log_sec": 512, "rota": true, "sched": null, "rq_size": 128, "disc_aln": 0, "disc_gran": "0B", "disc_max": "0B", "disc_zero": false, "wsame": "32M", "wwn": null, "rand": false, "pkname": "sda2", "hctl": null, "tran": null, "rev": null, "vendor": null}, {"name": "centos-swap", "maj_min": "253:1", "rm": false, "size": "2G", "ro": false, "type": "lvm", "mountpoint": "[SWAP]", "kname": "dm-1", "fstype": "swap", "label": null, "uuid": "615eb89d-bcbf-46ad-80e3-c483ef5c931f", "partlabel": null, "partuuid": null, "ra": 4096, "model": null, "serial": null, "state": "running", "owner": "root", "group": "disk", "mode": "brw-rw----", "alignment": 0, "min_io": 512, "opt_io": 0, "phy_sec": 512, "log_sec": 512, "rota": true, "sched": null, "rq_size": 128, "disc_aln": 0, "disc_gran": "0B", "disc_max": "0B", "disc_zero": false, "wsame": "32M", "wwn": null, "rand": false, "pkname": "sda2", "hctl": null, "tran": null, "rev": null, "vendor": null}, {"name": "sr0", "maj_min": "11:0", "rm": true, "size": "1024M", "ro": false, "type": "rom", "mountpoint": null, "kname": "sr0", "fstype": null, "label": null, "uuid": null, "partlabel": null, "partuuid": null, "ra": 128, "model": "VMware IDE CDR10", "serial": "10000000000000000001", "state": "running", "owner": "root", "group": "cdrom", "mode": "brw-rw----", "alignment": 0, "min_io": 512, "opt_io": 0, "phy_sec": 512, "log_sec": 512, "rota": true, "sched": "deadline", "rq_size": 128, "disc_aln": 0, "disc_gran": "0B", "disc_max": "0B", "disc_zero": false, "wsame": "0B", "wwn": null, "rand": true, "pkname": null, "hctl": "2:0:0:0", "tran": "ata", "rev": "1.00", "vendor": "NECVMWar"}]
[{"name":"sda","maj_min":"8:0","rm":false,"size":"20G","ro":false,"type":"disk","mountpoint":null,"kname":"sda","fstype":null,"label":null,"uuid":null,"partlabel":null,"partuuid":null,"ra":4096,"model":"VMware Virtual S","serial":null,"state":"running","owner":"root","group":"disk","mode":"brw-rw----","alignment":0,"min_io":512,"opt_io":0,"phy_sec":512,"log_sec":512,"rota":true,"sched":"deadline","rq_size":128,"disc_aln":0,"disc_gran":"0B","disc_max":"0B","disc_zero":false,"wsame":"32M","wwn":null,"rand":true,"pkname":null,"hctl":"0:0:0:0","tran":"spi","rev":"1.0","vendor":"VMware,","size_bytes":21474836480,"disc_gran_bytes":0,"disc_max_bytes":0,"wsame_bytes":33554432},{"name":"sda1","maj_min":"8:1","rm":false,"size":"1G","ro":false,"type":"part","mountpoint":"/boot","kname":"sda1","fstype":"xfs","label":null,"uuid":"05d927bb-5875-49e3-ada1-7f46cb31c932","partlabel":null,"partuuid":null,"ra":4096,"model":null,"serial":null,"state":null,"owner":"root","group":"disk","mode":"brw-rw----","alignment":0,"min_io":512,"opt_io":0,"phy_sec":512,"log_sec":512,"rota":true,"sched":"deadline","rq_size":128,"disc_aln":0,"disc_gran":"0B","disc_max":"0B","disc_zero":false,"wsame":"32M","wwn":null,"rand":true,"pkname":"sda","hctl":null,"tran":null,"rev":null,"vendor":null,"size_bytes":1073741824,"disc_gran_bytes":0,"disc_max_bytes":0,"wsame_bytes":33554432},{"name":"sda2","maj_min":"8:2","rm":false,"size":"19G","ro":false,"type":"part","mountpoint":null,"kname":"sda2","fstype":"LVM2_member","label":null,"uuid":"3klkIj-w1qk-DkJi-0XBJ-y3o7-i2Ac-vHqWBM","partlabel":null,"partuuid":null,"ra":4096,"model":null,"serial":null,"state":null,"owner":"root","group":"disk","mode":"brw-rw----","alignment":0,"min_io":512,"opt_io":0,"phy_sec":512,"log_sec":512,"rota":true,"sched":"deadline","rq_size":128,"disc_aln":0,"disc_gran":"0B","disc_max":"0B","disc_zero":false,"wsame":"32M","wwn":null,"rand":true,"pkname":"sda","hctl":null,"tran":null,"rev":null,"vendor":null,"size_bytes":20401094656,"disc_gran_bytes":0,"disc_max_bytes":0,"wsame_bytes":33554432},{"name":"centos-root","maj_min":"253:0","rm":false,"size":"17G","ro":false,"type":"lvm","mountpoint":"/","kname":"dm-0","fstype":"xfs","label":null,"uuid":"07d718ef-950c-4e5b-98e0-42a1147b77d9","partlabel":null,"partuuid":null,"ra":4096,"model":null,"serial":null,"state":"running","owner":"root","group":"disk","mode":"brw-rw----","alignment":0,"min_io":512,"opt_io":0,"phy_sec":512,"log_sec":512,"rota":true,"sched":null,"rq_size":128,"disc_aln":0,"disc_gran":"0B","disc_max":"0B","disc_zero":false,"wsame":"32M","wwn":null,"rand":false,"pkname":"sda2","hctl":null,"tran":null,"rev":null,"vendor":null,"size_bytes":18253611008,"disc_gran_bytes":0,"disc_max_bytes":0,"wsame_bytes":33554432},{"name":"centos-swap","maj_min":"253:1","rm":false,"size":"2G","ro":false,"type":"lvm","mountpoint":"[SWAP]","kname":"dm-1","fstype":"swap","label":null,"uuid":"615eb89d-bcbf-46ad-80e3-c483ef5c931f","partlabel":null,"partuuid":null,"ra":4096,"model":null,"serial":null,"state":"running","owner":"root","group":"disk","mode":"brw-rw----","alignment":0,"min_io":512,"opt_io":0,"phy_sec":512,"log_sec":512,"rota":true,"sched":null,"rq_size":128,"disc_aln":0,"disc_gran":"0B","disc_max":"0B","disc_zero":false,"wsame":"32M","wwn":null,"rand":false,"pkname":"sda2","hctl":null,"tran":null,"rev":null,"vendor":null,"size_bytes":2147483648,"disc_gran_bytes":0,"disc_max_bytes":0,"wsame_bytes":33554432},{"name":"sr0","maj_min":"11:0","rm":true,"size":"1024M","ro":false,"type":"rom","mountpoint":null,"kname":"sr0","fstype":null,"label":null,"uuid":null,"partlabel":null,"partuuid":null,"ra":128,"model":"VMware IDE CDR10","serial":"10000000000000000001","state":"running","owner":"root","group":"cdrom","mode":"brw-rw----","alignment":0,"min_io":512,"opt_io":0,"phy_sec":512,"log_sec":512,"rota":true,"sched":"deadline","rq_size":128,"disc_aln":0,"disc_gran":"0B","disc_max":"0B","disc_zero":false,"wsame":"0B","wwn":null,"rand":true,"pkname":null,"hctl":"2:0:0:0","tran":"ata","rev":"1.00","vendor":"NECVMWar","size_bytes":1073741824,"disc_gran_bytes":0,"disc_max_bytes":0,"wsame_bytes":0}]

View File

@ -1 +1 @@
[{"name": "sda", "maj_min": "8:0", "rm": false, "size": "20G", "ro": false, "type": "disk", "mountpoint": null}, {"name": "sda1", "maj_min": "8:1", "rm": false, "size": "1G", "ro": false, "type": "part", "mountpoint": "/boot"}, {"name": "sda2", "maj_min": "8:2", "rm": false, "size": "19G", "ro": false, "type": "part", "mountpoint": null}, {"name": "centos-root", "maj_min": "253:0", "rm": false, "size": "17G", "ro": false, "type": "lvm", "mountpoint": "/"}, {"name": "centos-swap", "maj_min": "253:1", "rm": false, "size": "2G", "ro": false, "type": "lvm", "mountpoint": "[SWAP]"}, {"name": "sr0", "maj_min": "11:0", "rm": true, "size": "1024M", "ro": false, "type": "rom", "mountpoint": null}]
[{"name":"sda","maj_min":"8:0","rm":false,"size":"20G","ro":false,"type":"disk","mountpoint":null,"size_bytes":21474836480},{"name":"sda1","maj_min":"8:1","rm":false,"size":"1G","ro":false,"type":"part","mountpoint":"/boot","size_bytes":1073741824},{"name":"sda2","maj_min":"8:2","rm":false,"size":"19G","ro":false,"type":"part","mountpoint":null,"size_bytes":20401094656},{"name":"centos-root","maj_min":"253:0","rm":false,"size":"17G","ro":false,"type":"lvm","mountpoint":"/","size_bytes":18253611008},{"name":"centos-swap","maj_min":"253:1","rm":false,"size":"2G","ro":false,"type":"lvm","mountpoint":"[SWAP]","size_bytes":2147483648},{"name":"sr0","maj_min":"11:0","rm":true,"size":"1024M","ro":false,"type":"rom","mountpoint":null,"size_bytes":1073741824}]

View File

@ -0,0 +1,20 @@
Controller CC:52:AF:17:6A:E4 (public)
Manufacturer: 0x000f (15)
Version: 0x05 (5)
Name: starbase
Alias: starbase
Class: 0x006c010c (7078156)
Powered: yes
PowerState: on
Discoverable: no
DiscoverableTimeout: 0x000000b4 (180)
Pairable: no
UUID: Handsfree (0000111e-0000-1000-8000-00805f9b34fb)
UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Handsfree Audio Gateway (0000111f-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d054F
Discovering: no

View File

@ -0,0 +1 @@
[{"filesystem":"/dev/disk3s1s1","mount_point":"/","options":["apfs","sealed","local","read-only","journaled"]},{"filesystem":"devfs","mount_point":"/dev","options":["devfs","local","nobrowse"]},{"filesystem":"/dev/disk3s6","mount_point":"/System/Volumes/VM","options":["apfs","local","noexec","journaled","noatime","nobrowse"]},{"filesystem":"/dev/disk3s2","mount_point":"/System/Volumes/Preboot","options":["apfs","local","journaled","nobrowse"]},{"filesystem":"/dev/disk3s4","mount_point":"/System/Volumes/Update","options":["apfs","local","journaled","nobrowse"]},{"filesystem":"/dev/disk2s2","mount_point":"/System/Volumes/xarts","options":["apfs","local","noexec","journaled","noatime","nobrowse"]},{"filesystem":"/dev/disk2s1","mount_point":"/System/Volumes/iSCPreboot","options":["apfs","local","journaled","nobrowse"]},{"filesystem":"/dev/disk2s3","mount_point":"/System/Volumes/Hardware","options":["apfs","local","journaled","nobrowse"]},{"filesystem":"/dev/disk3s5","mount_point":"/System/Volumes/Data","options":["apfs","local","journaled","nobrowse","protect","root data"]},{"filesystem":"map auto_home","mount_point":"/System/Volumes/Data/home","options":["autofs","automounted","nobrowse"]},{"filesystem":"MN - mydomain.com (ftp.mydomain.com):/","mount_point":"/Users/muescha/Library/Application Support/Mountain Duck/Volumes.noindex/MN - mydomain.com.localized","options":["nfs","asynchronous","nodev","nosuid","noowners","noatime","mounted by muescha"]},{"filesystem":"/dev/disk5s1","mount_point":"/Library/Developer/CoreSimulator/Volumes/iOS_21F79","options":["apfs","local","nodev","nosuid","read-only","journaled","noowners","noatime","nobrowse"]},{"filesystem":"/dev/disk7s1","mount_point":"/Library/Developer/CoreSimulator/Cryptex/Images/bundle/SimRuntimeBundle-A3CF7B3B-543B-4D71-BA03-12F939EA0B4D","options":["apfs","local","nodev","nosuid","read-only","journaled","noowners","noatime","nobrowse"]},{"filesystem":"/dev/disk9s1","mount_point":"/Library/Developer/CoreSimulator/Volumes/iOS_22C150","options":["apfs","sealed","local","nodev","nosuid","read-only","journaled","noowners","noatime","nobrowse"]}]

View File

@ -0,0 +1,14 @@
/dev/disk3s1s1 on / (apfs, sealed, local, read-only, journaled)
devfs on /dev (devfs, local, nobrowse)
/dev/disk3s6 on /System/Volumes/VM (apfs, local, noexec, journaled, noatime, nobrowse)
/dev/disk3s2 on /System/Volumes/Preboot (apfs, local, journaled, nobrowse)
/dev/disk3s4 on /System/Volumes/Update (apfs, local, journaled, nobrowse)
/dev/disk2s2 on /System/Volumes/xarts (apfs, local, noexec, journaled, noatime, nobrowse)
/dev/disk2s1 on /System/Volumes/iSCPreboot (apfs, local, journaled, nobrowse)
/dev/disk2s3 on /System/Volumes/Hardware (apfs, local, journaled, nobrowse)
/dev/disk3s5 on /System/Volumes/Data (apfs, local, journaled, nobrowse, protect, root data)
map auto_home on /System/Volumes/Data/home (autofs, automounted, nobrowse)
MN - mydomain.com (ftp.mydomain.com):/ on /Users/muescha/Library/Application Support/Mountain Duck/Volumes.noindex/MN - mydomain.com.localized (nfs, asynchronous, nodev, nosuid, noowners, noatime, mounted by muescha)
/dev/disk5s1 on /Library/Developer/CoreSimulator/Volumes/iOS_21F79 (apfs, local, nodev, nosuid, read-only, journaled, noowners, noatime, nobrowse)
/dev/disk7s1 on /Library/Developer/CoreSimulator/Cryptex/Images/bundle/SimRuntimeBundle-A3CF7B3B-543B-4D71-BA03-12F939EA0B4D (apfs, local, nodev, nosuid, read-only, journaled, noowners, noatime, nobrowse)
/dev/disk9s1 on /Library/Developer/CoreSimulator/Volumes/iOS_22C150 (apfs, sealed, local, nodev, nosuid, read-only, journaled, noowners, noatime, nobrowse)

Binary file not shown.

View File

@ -0,0 +1 @@
[{"tbs_certificate":{"version":"v3","serial_number":"37:12:43:a3:c9:eb:75:b7:61:6f:39:5f:0f:4d:a9:d4:6a:67:61:c2","signature":{"algorithm":"sha256_ecdsa","parameters":null},"issuer":{"common_name":"idna issues Inc."},"validity":{"not_before":1744299375,"not_after":2059659375,"not_before_iso":"2025-04-10T15:36:15+00:00","not_after_iso":"2035-04-08T15:36:15+00:00"},"subject":{"common_name":"idna issues Inc."},"subject_public_key_info":{"algorithm":{"algorithm":"ec","parameters":"secp256r1"},"public_key":"04:c4:e7:a0:b8:d0:5a:d3:77:86:e9:b2:b4:0d:4c:4f:52:25:0b:53:5b:21:5e:f1:50:1e:4f:6c:f4:8f:44:03:50:c2:ee:0e:61:2b:56:09:25:5c:4c:17:2a:78:cd:d2:ff:f5:8f:0e:68:eb:c9:4b:8a:18:0d:62:8d:9b:46:5f:71"},"issuer_unique_id":null,"subject_unique_id":null,"extensions":[{"extn_id":"subject_alt_name","critical":false,"extn_value":["sesam@xn--strae-oqa.de"]}],"serial_number_str":"314401798066465365584221074488388179068992315842"},"signature_algorithm":{"algorithm":"sha256_ecdsa","parameters":null},"signature_value":"30:46:02:21:00:9c:3b:38:eb:d6:52:e4:49:4b:4c:0a:19:04:56:45:66:31:4f:fd:c0:8d:ec:6c:c7:61:61:81:40:08:55:64:c2:02:21:00:f9:a1:38:ea:5a:f0:c1:2e:7c:c1:92:bd:f8:20:77:dd:50:63:5b:6d:7e:8a:35:28:97:bf:30:b0:db:d0:85:f1"}]

View File

@ -1 +1 @@
[{"chain": "INPUT", "rules": [{"pkts": 66, "bytes": 6034, "target": "ACCEPT", "prot": "all", "opt": null, "in": "lo", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0"}, {"pkts": 1137, "bytes": 318000, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate RELATED,ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "DROP", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate INVALID"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "tcp", "opt": null, "in": "*", "out": "*", "source": "15.15.15.0/24", "destination": "0.0.0.0/0", "options": "tcp dpt:22 ctstate NEW,ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "lo", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate RELATED,ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "DROP", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate INVALID"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "tcp", "opt": null, "in": "*", "out": "*", "source": "15.15.15.0/24", "destination": "0.0.0.0/0", "options": "tcp dpt:22 ctstate NEW,ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "lo", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate RELATED,ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "DROP", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate INVALID"}, {"pkts": 0, "bytes": 0, "target": "DROP", "prot": "all", "opt": null, "in": "lo", "out": "*", "source": "15.15.15.51", "destination": "0.0.0.0/0"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "tcp", "opt": null, "in": "*", "out": "*", "source": "15.15.15.0/24", "destination": "0.0.0.0/0", "options": "tcp dpt:22 ctstate NEW,ESTABLISHED"}]}, {"chain": "FORWARD", "rules": []}, {"chain": "OUTPUT", "rules": [{"pkts": 66, "bytes": 6034, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "lo", "source": "0.0.0.0/0", "destination": "0.0.0.0/0"}, {"pkts": 889, "bytes": 158000, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "tcp", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "tcp spt:22 ctstate ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "lo", "source": "0.0.0.0/0", "destination": "0.0.0.0/0"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "tcp", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "tcp spt:22 ctstate ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "lo", "source": "0.0.0.0/0", "destination": "0.0.0.0/0"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "all", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "ctstate ESTABLISHED"}, {"pkts": 0, "bytes": 0, "target": "ACCEPT", "prot": "tcp", "opt": null, "in": "*", "out": "*", "source": "0.0.0.0/0", "destination": "0.0.0.0/0", "options": "tcp spt:22 ctstate ESTABLISHED"}]}]
[{"chain":"INPUT","default_policy":"ACCEPT","default_packets":0,"default_bytes":0,"rules":[{"pkts":66,"bytes":6034,"target":"ACCEPT","prot":"all","opt":null,"in":"lo","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":1137,"bytes":318000,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate RELATED,ESTABLISHED"},{"pkts":0,"bytes":0,"target":"DROP","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate INVALID"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"tcp","opt":null,"in":"*","out":"*","source":"15.15.15.0/24","destination":"0.0.0.0/0","options":"tcp dpt:22 ctstate NEW,ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"lo","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate RELATED,ESTABLISHED"},{"pkts":0,"bytes":0,"target":"DROP","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate INVALID"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"tcp","opt":null,"in":"*","out":"*","source":"15.15.15.0/24","destination":"0.0.0.0/0","options":"tcp dpt:22 ctstate NEW,ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"lo","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate RELATED,ESTABLISHED"},{"pkts":0,"bytes":0,"target":"DROP","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate INVALID"},{"pkts":0,"bytes":0,"target":"DROP","prot":"all","opt":null,"in":"lo","out":"*","source":"15.15.15.51","destination":"0.0.0.0/0"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"tcp","opt":null,"in":"*","out":"*","source":"15.15.15.0/24","destination":"0.0.0.0/0","options":"tcp dpt:22 ctstate NEW,ESTABLISHED"}]},{"chain":"FORWARD","default_policy":"ACCEPT","default_packets":0,"default_bytes":0,"rules":[]},{"chain":"OUTPUT","default_policy":"ACCEPT","default_packets":4,"default_bytes":277,"rules":[{"pkts":66,"bytes":6034,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"lo","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":889,"bytes":158000,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"tcp","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"tcp spt:22 ctstate ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"lo","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"tcp","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"tcp spt:22 ctstate ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"lo","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"all","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate ESTABLISHED"},{"pkts":0,"bytes":0,"target":"ACCEPT","prot":"tcp","opt":null,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"tcp spt:22 ctstate ESTABLISHED"}]}]

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
[{"name": "fd0", "maj_min": "2:0", "rm": true, "size": "1.4M", "ro": false, "type": "disk", "mountpoint": null}, {"name": "loop0", "maj_min": "7:0", "rm": false, "size": "54.5M", "ro": true, "type": "loop", "mountpoint": "/snap/core18/1223"}, {"name": "loop1", "maj_min": "7:1", "rm": false, "size": "11M", "ro": true, "type": "loop", "mountpoint": "/snap/slcli/383"}, {"name": "loop2", "maj_min": "7:2", "rm": false, "size": "88.7M", "ro": true, "type": "loop", "mountpoint": "/snap/core/7396"}, {"name": "loop3", "maj_min": "7:3", "rm": false, "size": "66.5M", "ro": true, "type": "loop", "mountpoint": "/snap/google-cloud-sdk/103"}, {"name": "loop4", "maj_min": "7:4", "rm": false, "size": "66.5M", "ro": true, "type": "loop", "mountpoint": "/snap/google-cloud-sdk/104"}, {"name": "loop5", "maj_min": "7:5", "rm": false, "size": "54.4M", "ro": true, "type": "loop", "mountpoint": "/snap/core18/1074"}, {"name": "loop7", "maj_min": "7:7", "rm": false, "size": "8.6M", "ro": true, "type": "loop", "mountpoint": "/snap/doctl/187"}, {"name": "loop8", "maj_min": "7:8", "rm": false, "size": "3.1M", "ro": true, "type": "loop", "mountpoint": "/snap/stress-ng/847"}, {"name": "loop9", "maj_min": "7:9", "rm": false, "size": "8.6M", "ro": true, "type": "loop", "mountpoint": "/snap/doctl/215"}, {"name": "loop10", "maj_min": "7:10", "rm": false, "size": "89.1M", "ro": true, "type": "loop", "mountpoint": "/snap/core/7917"}, {"name": "loop11", "maj_min": "7:11", "rm": false, "size": "3.2M", "ro": true, "type": "loop", "mountpoint": "/snap/stress-ng/924"}, {"name": "sda", "maj_min": "8:0", "rm": false, "size": "20G", "ro": false, "type": "disk", "mountpoint": null}, {"name": "sda1", "maj_min": "8:1", "rm": false, "size": "1M", "ro": false, "type": "part", "mountpoint": null}, {"name": "sda2", "maj_min": "8:2", "rm": false, "size": "20G", "ro": false, "type": "part", "mountpoint": "/"}, {"name": "sr0", "maj_min": "11:0", "rm": true, "size": "64.8M", "ro": false, "type": "rom", "mountpoint": null}, {"name": "sr1", "maj_min": "11:1", "rm": true, "size": "848M", "ro": false, "type": "rom", "mountpoint": null}]
[{"name":"fd0","maj_min":"2:0","rm":true,"size":"1.4M","ro":false,"type":"disk","mountpoint":null,"size_bytes":1468006},{"name":"loop0","maj_min":"7:0","rm":false,"size":"54.5M","ro":true,"type":"loop","mountpoint":"/snap/core18/1223","size_bytes":57147392},{"name":"loop1","maj_min":"7:1","rm":false,"size":"11M","ro":true,"type":"loop","mountpoint":"/snap/slcli/383","size_bytes":11534336},{"name":"loop2","maj_min":"7:2","rm":false,"size":"88.7M","ro":true,"type":"loop","mountpoint":"/snap/core/7396","size_bytes":93008691},{"name":"loop3","maj_min":"7:3","rm":false,"size":"66.5M","ro":true,"type":"loop","mountpoint":"/snap/google-cloud-sdk/103","size_bytes":69730304},{"name":"loop4","maj_min":"7:4","rm":false,"size":"66.5M","ro":true,"type":"loop","mountpoint":"/snap/google-cloud-sdk/104","size_bytes":69730304},{"name":"loop5","maj_min":"7:5","rm":false,"size":"54.4M","ro":true,"type":"loop","mountpoint":"/snap/core18/1074","size_bytes":57042534},{"name":"loop7","maj_min":"7:7","rm":false,"size":"8.6M","ro":true,"type":"loop","mountpoint":"/snap/doctl/187","size_bytes":9017753},{"name":"loop8","maj_min":"7:8","rm":false,"size":"3.1M","ro":true,"type":"loop","mountpoint":"/snap/stress-ng/847","size_bytes":3250585},{"name":"loop9","maj_min":"7:9","rm":false,"size":"8.6M","ro":true,"type":"loop","mountpoint":"/snap/doctl/215","size_bytes":9017753},{"name":"loop10","maj_min":"7:10","rm":false,"size":"89.1M","ro":true,"type":"loop","mountpoint":"/snap/core/7917","size_bytes":93428121},{"name":"loop11","maj_min":"7:11","rm":false,"size":"3.2M","ro":true,"type":"loop","mountpoint":"/snap/stress-ng/924","size_bytes":3355443},{"name":"sda","maj_min":"8:0","rm":false,"size":"20G","ro":false,"type":"disk","mountpoint":null,"size_bytes":21474836480},{"name":"sda1","maj_min":"8:1","rm":false,"size":"1M","ro":false,"type":"part","mountpoint":null,"size_bytes":1048576},{"name":"sda2","maj_min":"8:2","rm":false,"size":"20G","ro":false,"type":"part","mountpoint":"/","size_bytes":21474836480},{"name":"sr0","maj_min":"11:0","rm":true,"size":"64.8M","ro":false,"type":"rom","mountpoint":null,"size_bytes":67947724},{"name":"sr1","maj_min":"11:1","rm":true,"size":"848M","ro":false,"type":"rom","mountpoint":null,"size_bytes":889192448}]

Binary file not shown.

View File

@ -22,27 +22,49 @@ class AmixerTests(unittest.TestCase):
self.test_files_json = [f'{file}.json' for file in self.TEST_FILES_NAME]
self.test_files_processed_json = [f'{file}-processed.json' for file in self.TEST_FILES_NAME]
def test_amixer_sget_nodata(self):
"""
Test 'amixer' with no data
"""
self.assertEqual(jc.parsers.amixer.parse('', quiet=True), {})
def test_amixer_sget(self):
for file_out, file_json, file_processed_json in zip(self.test_files_out, self.test_files_json,
self.test_files_processed_json):
with open(file_out, 'r') as f:
amixer_sget_raw_output: str = f.read()
amixer_sget_raw_output = f.read()
with open(file_json, 'r') as f:
expected_amixer_sget_json_output: str = f.read()
expected_amixer_sget_json_map: dict = json.loads(expected_amixer_sget_json_output)
expected_amixer_sget_json_output = f.read()
expected_amixer_sget_json_map = json.loads(expected_amixer_sget_json_output)
with open(file_processed_json, 'r') as f:
expected_amixer_sget_processed_json_output: str = f.read()
expected_amixer_sget_processed_json_map: dict = json.loads(expected_amixer_sget_processed_json_output)
expected_amixer_sget_processed_json_output = f.read()
expected_amixer_sget_processed_json_map = json.loads(expected_amixer_sget_processed_json_output)
# Tests for raw=True
amixer_sget_json_map: dict = jc.parse(self.AMIXER_CMD, amixer_sget_raw_output, raw=True,
amixer_sget_json_map = jc.parse(self.AMIXER_CMD, amixer_sget_raw_output, raw=True,
quiet=True)
self.assertEqual(amixer_sget_json_map, expected_amixer_sget_json_map)
# Tests for raw=False process
amixer_sget_json_processed_map: dict = jc.parse(self.AMIXER_CMD, amixer_sget_raw_output, raw=False,
amixer_sget_json_processed_map = jc.parse(self.AMIXER_CMD, amixer_sget_raw_output, raw=False,
quiet=True)
self.assertEqual(amixer_sget_json_processed_map, expected_amixer_sget_processed_json_map)
def test_amixer_missing_db(self):
data = '''Simple mixer control 'Master',0
Capabilities: pvolume pswitch pswitch-joined
Playback channels: Front Left - Front Right
Limits: Playback 0 - 65536
Mono:
Front Left: Playback 55039 [84%] [on]
Front Right: Playback 54383 [83%] [on]
Simple mixer control 'Capture',0
Capabilities: cvolume cswitch cswitch-joined
Capture channels: Front Left - Front Right
Limits: Capture 0 - 65536
Front Left: Capture 24672 [38%] [on]
Front Right: Capture 24672 [38%] [on]'''
expected = {"control_name":"Master","capabilities":["cvolume","cswitch","cswitch-joined"],"playback_channels":["Front Left","Front Right"],"limits":{"playback_min":0,"playback_max":65536},"front_left":{"playback_value":24672,"percentage":38,"db":0.0,"status":True},"front_right":{"playback_value":24672,"percentage":38,"db":0.0,"status":True}}
self.assertEqual(expected, jc.parsers.amixer.parse(data, quiet=True))
if __name__ == '__main__':
unittest.main()

View File

@ -105,6 +105,47 @@ class BluetoothctlTests(unittest.TestCase):
for k, v in expected.items():
self.assertEqual(v, actual[0][k], f"Controller regex failed on {k}")
def test_bluetoothctl_controller_2(self):
"""
Test 'bluetoothctl' with controller 2
"""
with open("tests/fixtures/generic/bluetoothctl_controller_2.out", "r") as f:
output = f.read()
actual = parse(output, quiet=True)
self.assertIsNotNone(actual)
self.assertIsNotNone(actual[0])
expected = {
"address": "CC:52:AF:17:6A:E4",
"is_public": True,
"name": "starbase",
"alias": "starbase",
"class": "0x006c010c (7078156)",
"powered": "yes",
"power_state": "on",
"discoverable": "no",
"discoverable_timeout": "0x000000b4 (180)",
"pairable": "no",
"uuids": [
"Handsfree (0000111e-0000-1000-8000-00805f9b34fb)",
"Audio Source (0000110a-0000-1000-8000-00805f9b34fb)",
"Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)",
"PnP Information (00001200-0000-1000-8000-00805f9b34fb)",
"A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)",
"A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)",
"Handsfree Audio Gateway (0000111f-0000-1000-8000-00805f9b34fb)"
],
"modalias": "usb:v1D6Bp0246d054F",
"discovering": "no"
}
if actual:
for k, v in expected.items():
self.assertEqual(v, actual[0][k], f"Controller regex failed on {k}")
def test_bluetoothctl_controller_with_manufacturer(self):
"""
Test 'bluetoothctl' with controller having manufacturer attr

View File

@ -200,7 +200,7 @@ class MyTests(unittest.TestCase):
128627559125 172804718595966 INPUT_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0
26599 1082920 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
1761 79571 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited'''
expected = [{"chain":"INPUT","rules":[{"pkts":11291792498,"bytes":217331852907122,"target":"ACCEPT","prot":"all","opt":None,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate RELATED,ESTABLISHED"},{"pkts":555958,"bytes":33533576,"target":"ACCEPT","prot":"all","opt":None,"in":"lo","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":128628404869,"bytes":172804745659762,"target":"INPUT_direct","prot":"all","opt":None,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":128627559128,"bytes":172804718596050,"target":"INPUT_ZONES_SOURCE","prot":"all","opt":None,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":128627559125,"bytes":172804718595966,"target":"INPUT_ZONES","prot":"all","opt":None,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0"},{"pkts":26599,"bytes":1082920,"target":"DROP","prot":"all","opt":None,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"ctstate INVALID"},{"pkts":1761,"bytes":79571,"target":"REJECT","prot":"all","opt":None,"in":"*","out":"*","source":"0.0.0.0/0","destination":"0.0.0.0/0","options":"reject-with icmp-host-prohibited"}]}]
expected = [{'chain': 'INPUT', 'default_policy': 'ACCEPT', 'default_packets': 0, 'default_bytes': 0, 'rules': [{'pkts': 11291792498, 'bytes': 217331852907122, 'target': 'ACCEPT', 'prot': 'all', 'opt': None, 'in': '*', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0', 'options': 'ctstate RELATED,ESTABLISHED'}, {'pkts': 555958, 'bytes': 33533576, 'target': 'ACCEPT', 'prot': 'all', 'opt': None, 'in': 'lo', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0'}, {'pkts': 128628404869, 'bytes': 172804745659762, 'target': 'INPUT_direct', 'prot': 'all', 'opt': None, 'in': '*', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0'}, {'pkts': 128627559128, 'bytes': 172804718596050, 'target': 'INPUT_ZONES_SOURCE', 'prot': 'all', 'opt': None, 'in': '*', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0'}, {'pkts': 128627559125, 'bytes': 172804718595966, 'target': 'INPUT_ZONES', 'prot': 'all', 'opt': None, 'in': '*', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0'}, {'pkts': 26599, 'bytes': 1082920, 'target': 'DROP', 'prot': 'all', 'opt': None, 'in': '*', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0', 'options': 'ctstate INVALID'}, {'pkts': 1761, 'bytes': 79571, 'target': 'REJECT', 'prot': 'all', 'opt': None, 'in': '*', 'out': '*', 'source': '0.0.0.0/0', 'destination': '0.0.0.0/0', 'options': 'reject-with icmp-host-prohibited'}]}]
self.assertEqual(jc.parsers.iptables.parse(data, quiet=True), expected)

View File

@ -65,6 +65,24 @@ class MyTests(unittest.TestCase):
"""
self.assertEqual(jc.parsers.lsblk.parse(self.ubuntu_18_4_lsblk_allcols, quiet=True), self.ubuntu_18_4_lsblk_allcols_json)
def test_lsblk_multiple_mountpoints(self):
"""
Test 'lsblk' with multiple mountpoints
"""
data = '''NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 5368709120000 0 disk
|-sda1 8:1 0 1048576 0 part
|-sda2 8:2 0 1073741824 0 part /boot
|-sda3 8:3 0 1073741824 0 part /boot/efi
`-sda4 8:4 0 51536461824 0 part
|-almalinux-root 253:0 0 36075208704 0 lvm /
|-almalinux-docker 253:1 0 1073741824 0 lvm /opt/docker
|-almalinux-home 253:2 0 5368709120 0 lvm /home
`-almalinux-opt 253:3 0 9017753600 0 lvm /var/lib/kafka
/opt
sr0 11:0 1 1073741312 0 rom'''
expected = [{"name":"sda","maj_min":"8:0","rm":False,"size":"5368709120000","ro":False,"type":"disk","mountpoints":[],"size_bytes":5368709120000},{"name":"sda1","maj_min":"8:1","rm":False,"size":"1048576","ro":False,"type":"part","mountpoints":[],"size_bytes":1048576},{"name":"sda2","maj_min":"8:2","rm":False,"size":"1073741824","ro":False,"type":"part","mountpoints":["/boot"],"size_bytes":1073741824},{"name":"sda3","maj_min":"8:3","rm":False,"size":"1073741824","ro":False,"type":"part","mountpoints":["/boot/efi"],"size_bytes":1073741824},{"name":"sda4","maj_min":"8:4","rm":False,"size":"51536461824","ro":False,"type":"part","mountpoints":[],"size_bytes":51536461824},{"name":"almalinux-root","maj_min":"253:0","rm":False,"size":"36075208704","ro":False,"type":"lvm","mountpoints":["/"],"size_bytes":36075208704},{"name":"almalinux-docker","maj_min":"253:1","rm":False,"size":"1073741824","ro":False,"type":"lvm","mountpoints":["/opt/docker"],"size_bytes":1073741824},{"name":"almalinux-home","maj_min":"253:2","rm":False,"size":"5368709120","ro":False,"type":"lvm","mountpoints":["/home"],"size_bytes":5368709120},{"name":"almalinux-opt","maj_min":"253:3","rm":False,"size":"9017753600","ro":False,"type":"lvm","mountpoints":["/var/lib/kafka","/opt"],"size_bytes":9017753600},{"name":"sr0","maj_min":"11:0","rm":True,"size":"1073741312","ro":False,"type":"rom","mountpoints":[],"size_bytes":1073741312}]
self.assertEqual(jc.parsers.lsblk.parse(data, quiet=True), expected)
if __name__ == '__main__':
unittest.main()

View File

@ -30,6 +30,9 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/mount-spaces-in-filename.out'), 'r', encoding='utf-8') as f:
generic_mount_spaces_in_filename = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/mount-parens-in-filesystem.out'), 'r', encoding='utf-8') as f:
generic_mount_parens_in_filesystem = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/mount.json'), 'r', encoding='utf-8') as f:
@ -53,6 +56,9 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/mount-spaces-in-filename.json'), 'r', encoding='utf-8') as f:
generic_mount_spaces_in_filename_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/mount-parens-in-filesystem.json'), 'r', encoding='utf-8') as f:
generic_mount_parens_in_filesystem_json = json.loads(f.read())
def test_mount_nodata(self):
"""
@ -102,6 +108,12 @@ class MyTests(unittest.TestCase):
"""
self.assertEqual(jc.parsers.mount.parse(self.generic_mount_spaces_in_filename, quiet=True), self.generic_mount_spaces_in_filename_json)
def test_mount_parens_in_filesystem(self):
"""
Test 'mount' with parenthesis in the filesystem
"""
self.assertEqual(jc.parsers.mount.parse(self.generic_mount_parens_in_filesystem, quiet=True), self.generic_mount_parens_in_filesystem_json)
if __name__ == '__main__':
unittest.main()

View File

@ -185,6 +185,117 @@ class MyTests(unittest.TestCase):
"""
self.assertEqual(jc.parsers.nmcli.parse(self.fedora32_nmcli_device_show, quiet=True), self.fedora32_nmcli_device_show_json)
def test_nmcli_team_config(self):
"""
Test nmcli with team.config JSON value
"""
data = '''connection.id: Team connection 1
connection.uuid: 258e02c2-d9f9-44bb-8d27-887e11aa1828
connection.stable-id: --
connection.type: team
connection.interface-name: team0
connection.autoconnect: yes
connection.autoconnect-priority: 0
connection.autoconnect-retries: -1 (default)
connection.multi-connect: 0 (default)
connection.auth-retries: -1
connection.timestamp: 0
connection.read-only: no
connection.permissions: --
connection.zone: --
connection.master: --
connection.slave-type: --
connection.autoconnect-slaves: -1 (default)
connection.secondaries: --
connection.gateway-ping-timeout: 0
connection.metered: unknown
connection.lldp: default
connection.mdns: -1 (default)
connection.llmnr: -1 (default)
connection.dns-over-tls: -1 (default)
connection.wait-device-timeout: -1
ipv4.method: auto
ipv4.dns: --
ipv4.dns-search: --
ipv4.dns-options: --
ipv4.dns-priority: 0
ipv4.addresses: --
ipv4.gateway: --
ipv4.routes: --
ipv4.route-metric: -1
ipv4.route-table: 0 (unspec)
ipv4.routing-rules: --
ipv4.ignore-auto-routes: no
ipv4.ignore-auto-dns: no
ipv4.dhcp-client-id: --
ipv4.dhcp-iaid: --
ipv4.dhcp-timeout: 0 (default)
ipv4.dhcp-send-hostname: yes
ipv4.dhcp-hostname: --
ipv4.dhcp-fqdn: --
ipv4.dhcp-hostname-flags: 0x0 (none)
ipv4.never-default: no
ipv4.may-fail: yes
ipv4.required-timeout: -1 (default)
ipv4.dad-timeout: -1 (default)
ipv4.dhcp-vendor-class-identifier: --
ipv4.dhcp-reject-servers: --
ipv6.method: auto
ipv6.dns: --
ipv6.dns-search: --
ipv6.dns-options: --
ipv6.dns-priority: 0
ipv6.addresses: --
ipv6.gateway: --
ipv6.routes: --
ipv6.route-metric: -1
ipv6.route-table: 0 (unspec)
ipv6.routing-rules: --
ipv6.ignore-auto-routes: no
ipv6.ignore-auto-dns: no
ipv6.never-default: no
ipv6.may-fail: yes
ipv6.required-timeout: -1 (default)
ipv6.ip6-privacy: -1 (unknown)
ipv6.addr-gen-mode: stable-privacy
ipv6.ra-timeout: 0 (default)
ipv6.dhcp-duid: --
ipv6.dhcp-iaid: --
ipv6.dhcp-timeout: 0 (default)
ipv6.dhcp-send-hostname: yes
ipv6.dhcp-hostname: --
ipv6.dhcp-hostname-flags: 0x0 (none)
ipv6.token: --
team.config: {
"runner": {
"name": "roundrobin"
},
"link_watch": {
"name": "ethtool"
}
}
team.notify-peers-count: -1 (unset)
team.notify-peers-interval: -1 (unset)
team.mcast-rejoin-count: -1 (unset)
team.mcast-rejoin-interval: -1 (unset)
team.runner: roundrobin
team.runner-hwaddr-policy: --
team.runner-tx-hash: --
team.runner-tx-balancer: --
team.runner-tx-balancer-interval: -1 (unset)
team.runner-active: yes
team.runner-fast-rate: no
team.runner-sys-prio: -1 (unset)
team.runner-min-ports: -1 (unset)
team.runner-agg-select-policy: --
team.link-watchers: name=ethtool
proxy.method: none
proxy.browser-only: no
proxy.pac-url: --
proxy.pac-script: --'''
expected = [{'connection_id': 'Team connection 1', 'connection_uuid': '258e02c2-d9f9-44bb-8d27-887e11aa1828', 'connection_stable_id': None, 'connection_type': 'team', 'connection_interface_name': 'team0', 'connection_autoconnect': 'yes', 'connection_autoconnect_priority': 0, 'connection_autoconnect_retries': -1, 'connection_autoconnect_retries_text': 'default', 'connection_multi_connect': 0, 'connection_multi_connect_text': 'default', 'connection_auth_retries': -1, 'connection_timestamp': 0, 'connection_read_only': 'no', 'connection_permissions': None, 'connection_zone': None, 'connection_master': None, 'connection_slave_type': None, 'connection_autoconnect_slaves': -1, 'connection_autoconnect_slaves_text': 'default', 'connection_secondaries': None, 'connection_gateway_ping_timeout': 0, 'connection_metered': 'unknown', 'connection_lldp': 'default', 'connection_mdns': -1, 'connection_mdns_text': 'default', 'connection_llmnr': -1, 'connection_llmnr_text': 'default', 'connection_dns_over_tls': -1, 'connection_dns_over_tls_text': 'default', 'connection_wait_device_timeout': -1, 'ipv4_method': 'auto', 'ipv4_dns': None, 'ipv4_dns_search': None, 'ipv4_dns_options': None, 'ipv4_dns_priority': 0, 'ipv4_addresses': None, 'ipv4_gateway': None, 'ipv4_routes': None, 'ipv4_route_metric': -1, 'ipv4_route_table': 0, 'ipv4_route_table_text': 'unspec', 'ipv4_routing_rules': None, 'ipv4_ignore_auto_routes': 'no', 'ipv4_ignore_auto_dns': 'no', 'ipv4_dhcp_client_id': None, 'ipv4_dhcp_iaid': None, 'ipv4_dhcp_timeout': 0, 'ipv4_dhcp_timeout_text': 'default', 'ipv4_dhcp_send_hostname': 'yes', 'ipv4_dhcp_hostname': None, 'ipv4_dhcp_fqdn': None, 'ipv4_dhcp_hostname_flags': '0x0', 'ipv4_dhcp_hostname_flags_text': 'none', 'ipv4_never_default': 'no', 'ipv4_may_fail': 'yes', 'ipv4_required_timeout': -1, 'ipv4_required_timeout_text': 'default', 'ipv4_dad_timeout': -1, 'ipv4_dad_timeout_text': 'default', 'ipv4_dhcp_vendor_class_identifier': None, 'ipv4_dhcp_reject_servers': None, 'ipv6_method': 'auto', 'ipv6_dns': None, 'ipv6_dns_search': None, 'ipv6_dns_options': None, 'ipv6_dns_priority': 0, 'ipv6_addresses': None, 'ipv6_gateway': None, 'ipv6_routes': None, 'ipv6_route_metric': -1, 'ipv6_route_table': 0, 'ipv6_route_table_text': 'unspec', 'ipv6_routing_rules': None, 'ipv6_ignore_auto_routes': 'no', 'ipv6_ignore_auto_dns': 'no', 'ipv6_never_default': 'no', 'ipv6_may_fail': 'yes', 'ipv6_required_timeout': -1, 'ipv6_required_timeout_text': 'default', 'ipv6_ip6_privacy': -1, 'ipv6_ip6_privacy_text': 'unknown', 'ipv6_addr_gen_mode': 'stable-privacy', 'ipv6_ra_timeout': 0, 'ipv6_ra_timeout_text': 'default', 'ipv6_dhcp_duid': None, 'ipv6_dhcp_iaid': None, 'ipv6_dhcp_timeout': 0, 'ipv6_dhcp_timeout_text': 'default', 'ipv6_dhcp_send_hostname': 'yes', 'ipv6_dhcp_hostname': None, 'ipv6_dhcp_hostname_flags': '0x0', 'ipv6_dhcp_hostname_flags_text': 'none', 'ipv6_token': None, 'team_config': {'runner': {'name': 'roundrobin'}, 'link_watch': {'name': 'ethtool'}}, 'team_notify_peers_count': -1, 'team_notify_peers_count_text': 'unset', 'team_notify_peers_interval': -1, 'team_notify_peers_interval_text': 'unset', 'team_mcast_rejoin_count': -1, 'team_mcast_rejoin_count_text': 'unset', 'team_mcast_rejoin_interval': -1, 'team_mcast_rejoin_interval_text': 'unset', 'team_runner': 'roundrobin', 'team_runner_hwaddr_policy': None, 'team_runner_tx_hash': None, 'team_runner_tx_balancer': None, 'team_runner_tx_balancer_interval': -1, 'team_runner_tx_balancer_interval_text': 'unset', 'team_runner_active': 'yes', 'team_runner_fast_rate': 'no', 'team_runner_sys_prio': -1, 'team_runner_sys_prio_text': 'unset', 'team_runner_min_ports': -1, 'team_runner_min_ports_text': 'unset', 'team_runner_agg_select_policy': None, 'team_link_watchers': 'name=ethtool', 'proxy_method': 'none', 'proxy_browser_only': 'no', 'proxy_pac_url': None, 'proxy_pac_script': None}]
self.assertEqual(jc.parsers.nmcli.parse(data, quiet=True), expected)
if __name__ == '__main__':
unittest.main()

View File

@ -113,6 +113,37 @@ class MyTests(unittest.TestCase):
"""
self.assertEqual(jc.parsers.time.parse(self.osx_10_14_6_time_lp, quiet=True), self.osx_10_14_6_time_lp_json)
def test_time_no_centiseconds(self):
"""
Test 'time' output with no centiseconds data
"""
data = ''' Command being timed: "echo"
User time (seconds): 5156.20
System time (seconds): 0.05
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 1:25:56
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 21760
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 4975
Voluntary context switches: 1
Involuntary context switches: 8159
Swaps: 0
File system inputs: 0
File system outputs: 6272
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0'''
expected = {"command_being_timed":"echo","user_time":5156.2,"system_time":0.05,"cpu_percent":99,"elapsed_time":"1:25:56","average_shared_text_size":0,"average_unshared_data_size":0,"average_stack_size":0,"average_total_size":0,"maximum_resident_set_size":21760,"average_resident_set_size":0,"major_pagefaults":0,"minor_pagefaults":4975,"voluntary_context_switches":1,"involuntary_context_switches":8159,"swaps":0,"block_input_operations":0,"block_output_operations":6272,"messages_sent":0,"messages_received":0,"signals_delivered":0,"page_size":4096,"exit_status":0,"elapsed_time_hours":1,"elapsed_time_minutes":25,"elapsed_time_seconds":56,"elapsed_time_centiseconds":0,"elapsed_time_total_seconds":5156.0}
self.assertEqual(jc.parsers.time.parse(data, quiet=True), expected)
if __name__ == '__main__':
unittest.main()

View File

@ -33,6 +33,9 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-negative-serial.pem'), 'rb') as f:
x509_cert_negative_serial = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-cert-bad-email2.der'), 'rb') as f:
x509_cert_bad_email2 = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-ca-cert.json'), 'r', encoding='utf-8') as f:
x509_ca_cert_json = json.loads(f.read())
@ -58,6 +61,9 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-negative-serial.json'), 'r', encoding='utf-8') as f:
x509_cert_negative_serial_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-cert-bad-email2.json'), 'r', encoding='utf-8') as f:
x509_cert_bad_email2_json = json.loads(f.read())
def test_x509_cert_nodata(self):
"""
@ -113,6 +119,12 @@ class MyTests(unittest.TestCase):
"""
self.assertEqual(jc.parsers.x509_cert.parse(self.x509_cert_negative_serial, quiet=True), self.x509_cert_negative_serial_json)
def test_x509_cert_bad_email2(self):
"""
Test 'cat x509-cert-bad-email2.der' (DER file with a non-compliant email address - IDNA2008 encoded)
"""
self.assertEqual(jc.parsers.x509_cert.parse(self.x509_cert_bad_email2, quiet=True), self.x509_cert_bad_email2_json)
if __name__ == '__main__':
unittest.main()