diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index aa92ddc..dfb79d2 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -27,8 +27,8 @@ jobs: - python-version: '3.13' os: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 275dbfc..57b728d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,8 +30,8 @@ jobs: - python-version: '3.13' os: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -50,10 +50,10 @@ jobs: needs: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: '3.10' @@ -79,7 +79,7 @@ jobs: fi - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 with: # Auto-generate release notes (editable after creation) generate_release_notes: true diff --git a/README.md b/README.md index 2763829..725a09e 100644 --- a/README.md +++ b/README.md @@ -293,9 +293,11 @@ Connect to a Wi-Fi network specified by SSID or BSSID. The `wait` argument applies the same effect to the command as the `--wait` option. If it is omitted, the default behavior is followed. +If `password` is `None`, the password option is omitted from the command. This allows connecting to open networks or known networks that already have credentials stored. + ``` nmcli.device.wifi_connect(ssid: str, - password: str, + password: Optional[str] = None, ifname: str = None, wait: int = None) -> None ``` @@ -509,6 +511,10 @@ nmcli.set_lang(lang: str) -> None ## Change Log +### 1.8.0 + +- Allow `nmcli.device.wifi_connect` to accept `None` as password to connect to open or known networks without specifying a password. + ### 1.7.0 - Added `nmcli.connection.show_all` method with active filtering support diff --git a/nmcli/_device.py b/nmcli/_device.py index 79216ba..8ea8b27 100644 --- a/nmcli/_device.py +++ b/nmcli/_device.py @@ -1,5 +1,5 @@ import re -from typing import List, Tuple +from typing import List, Optional, Tuple from ._exception import ConnectionActivateFailedException from ._helper import add_fields_option_if_needed, add_wait_option_if_needed @@ -75,7 +75,7 @@ def wifi(self, ifname: str = None, rescan: bool = None) -> List[DeviceWifi]: def wifi_connect(self, ssid: str, - password: str, + password: Optional[str] = None, ifname: str = None, wait: int = None) -> None: raise NotImplementedError @@ -182,13 +182,13 @@ def wifi(self, ifname: str = None, rescan: bool = None) -> List[DeviceWifi]: def wifi_connect(self, ssid: str, - password: str | None, + password: Optional[str] = None, ifname: str = None, wait: int = None) -> None: cmd = add_wait_option_if_needed( wait) + ['device', 'wifi', 'connect', ssid] if password is not None: - cmd += ['password', password] + cmd += ['password', password] if ifname is not None: cmd += ['ifname', ifname] r = self._syscmd.nmcli(cmd) diff --git a/nmcli/dummy/_device.py b/nmcli/dummy/_device.py index 10d9c01..c5ed238 100644 --- a/nmcli/dummy/_device.py +++ b/nmcli/dummy/_device.py @@ -1,4 +1,4 @@ -from typing import List, Tuple +from typing import List, Optional, Tuple from .._device import DeviceControlInterface, DeviceDetails from ..data.device import Device, DeviceWifi @@ -126,7 +126,7 @@ def wifi(self, ifname: str = None, rescan: bool = None) -> List[DeviceWifi]: def wifi_connect(self, ssid: str, - password: str, + password: Optional[str] = None, ifname: str = None, wait: int = None) -> None: self._raise_error_if_needed() diff --git a/pyproject.toml b/pyproject.toml index 521b210..c1ef2a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "nmcli" -version = "1.7.0" +version = "1.8.0" description = "A python wrapper library for the network-manager cli client" readme = "README.md" authors = [{name = "ushiboy"}] diff --git a/tests/dummy/test_device.py b/tests/dummy/test_device.py index a4ee880..170cf08 100644 --- a/tests/dummy/test_device.py +++ b/tests/dummy/test_device.py @@ -149,6 +149,20 @@ def test_wifi_connect(): assert c.wifi_connect_args[2] == (ssid, password, ifname, 10) +def test_wifi_connect_without_password(): + c = DummyDeviceControl() + ssid = 'ssid' + ifname = 'wlan0' + c.wifi_connect(ssid, None) + assert c.wifi_connect_args[0] == (ssid, None, None, None) + c.wifi_connect(ssid, None, ifname) + assert c.wifi_connect_args[1] == (ssid, None, ifname, None) + c.wifi_connect(ssid, None, ifname, wait=10) + assert c.wifi_connect_args[2] == (ssid, None, ifname, 10) + c.wifi_connect(ssid) + assert c.wifi_connect_args[3] == (ssid, None, None, None) + + def test_wifi_connect_when_raise_error(): c = DummyDeviceControl(raise_error=Exception) ssid = 'ssid' diff --git a/tests/test_device.py b/tests/test_device.py index 2b1576d..6e57592 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -326,6 +326,9 @@ def test_wifi_connect_without_password(): assert s.passed_parameters == [ '--wait', '10', 'device', 'wifi', 'connect', ssid] + device.wifi_connect(ssid) + assert s.passed_parameters == ['device', 'wifi', 'connect', ssid] + def test_wifi_connect_when_connection_activate_failed(): s = DummySystemCommand( diff --git a/tests/test_general.py b/tests/test_general.py index 870828f..6c2520b 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -59,7 +59,8 @@ def test_reload_with_all_valid_flags(): s = DummySystemCommand() general = GeneralControl(s) general.reload(['conf', 'dns-rc', 'dns-full']) - assert s.passed_parameters == ['general', 'reload', 'conf', 'dns-rc', 'dns-full'] + assert s.passed_parameters == ['general', + 'reload', 'conf', 'dns-rc', 'dns-full'] def test_reload_with_invalid_flag():