From 870934c2f7291533630744b14e37499a8e018c96 Mon Sep 17 00:00:00 2001 From: dherrada Date: Tue, 9 Nov 2021 13:31:14 -0500 Subject: [PATCH 01/56] Updated readthedocs file Signed-off-by: dherrada --- .readthedocs.yaml | 15 +++++++++++++++ .readthedocs.yml | 7 ------- 2 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 .readthedocs.yaml delete mode 100644 .readthedocs.yml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..95ec218 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +python: + version: "3.6" + install: + - requirements: docs/requirements.txt + - requirements: requirements.txt diff --git a/.readthedocs.yml b/.readthedocs.yml deleted file mode 100644 index 49dcab3..0000000 --- a/.readthedocs.yml +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries -# -# SPDX-License-Identifier: Unlicense - -python: - version: 3 -requirements_file: docs/requirements.txt From e3c86b3bf7a1a8b15301a6573bef612a5acb7e8d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 23 Nov 2021 13:01:48 -0600 Subject: [PATCH 02/56] update rtd py version --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 95ec218..1335112 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -9,7 +9,7 @@ version: 2 python: - version: "3.6" + version: "3.7" install: - requirements: docs/requirements.txt - requirements: requirements.txt From 0275375102e074160b8fc62384f2aa64d76bc2ab Mon Sep 17 00:00:00 2001 From: dherrada Date: Thu, 13 Jan 2022 16:27:30 -0500 Subject: [PATCH 03/56] First part of patch Signed-off-by: dherrada --- .../PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md | 2 +- .github/workflows/build.yml | 6 +++--- .github/workflows/release.yml | 8 ++++---- .readthedocs.yaml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md b/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md index 71ef8f8..8de294e 100644 --- a/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md +++ b/.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md @@ -4,7 +4,7 @@ Thank you for contributing! Before you submit a pull request, please read the following. -Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://circuitpython.readthedocs.io/en/latest/docs/design_guide.html +Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca35544..474520d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,10 +22,10 @@ jobs: awk -F '\/' '{ print tolower($2) }' | tr '_' '-' ) - - name: Set up Python 3.7 - uses: actions/setup-python@v1 + - name: Set up Python 3.x + uses: actions/setup-python@v2 with: - python-version: 3.7 + python-version: "3.x" - name: Versions run: | python3 --version diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d0015a..a65e5de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,10 +24,10 @@ jobs: awk -F '\/' '{ print tolower($2) }' | tr '_' '-' ) - - name: Set up Python 3.6 - uses: actions/setup-python@v1 + - name: Set up Python 3.x + uses: actions/setup-python@v2 with: - python-version: 3.6 + python-version: "3.x" - name: Versions run: | python3 --version @@ -67,7 +67,7 @@ jobs: echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) - name: Set up Python if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1335112..f8b2891 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -9,7 +9,7 @@ version: 2 python: - version: "3.7" + version: "3.x" install: - requirements: docs/requirements.txt - requirements: requirements.txt From f3372ce5fc2c3f646d01ef6421912261a69a3bf3 Mon Sep 17 00:00:00 2001 From: dherrada Date: Mon, 24 Jan 2022 16:46:16 -0500 Subject: [PATCH 04/56] Updated docs link, updated python docs link, updated setup.py --- README.rst | 4 ++-- docs/conf.py | 6 +++--- docs/index.rst | 2 +- setup.py | 2 -- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 34e640f..6faaa80 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ Introduction ============ .. image:: https://readthedocs.org/projects/adafruit-circuitpython-fona/badge/?version=latest - :target: https://circuitpython.readthedocs.io/projects/fona/en/latest/ + :target: https://docs.circuitpython.org/projects/fona/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/discord/327254708534116352.svg @@ -64,7 +64,7 @@ Please see the examples directory for code usage. Documentation ============= -API documentation for this library can be found on `Read the Docs `_. +API documentation for this library can be found on `Read the Docs `_. Contributing ============ diff --git a/docs/conf.py b/docs/conf.py index 857e60e..cda1c23 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,12 +29,12 @@ intersphinx_mapping = { - "python": ("https://docs.python.org/3.4", None), + "python": ("https://docs.python.org/3", None), "BusDevice": ( - "https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", + "https://docs.circuitpython.org/projects/busdevice/en/latest/", None, ), - "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), + "CircuitPython": ("https://docs.circuitpython.org/en/latest/", None), } # Add any paths that contain templates here, relative to this directory. diff --git a/docs/index.rst b/docs/index.rst index f0dbc6f..d27a218 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -33,7 +33,7 @@ Table of Contents :caption: Other Links Download - CircuitPython Reference Documentation + CircuitPython Reference Documentation CircuitPython Support Forum Discord Chat Adafruit Learning System diff --git a/setup.py b/setup.py index 9b238e3..52a843c 100644 --- a/setup.py +++ b/setup.py @@ -44,8 +44,6 @@ "Topic :: System :: Hardware", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", ], # What does your project relate to? keywords="adafruit blinka circuitpython micropython fona fona, cellular", From 04b7119bf551e13dd812b962aab8626c9cd7ff72 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Wed, 9 Feb 2022 12:58:13 -0500 Subject: [PATCH 05/56] Consolidate Documentation sections of README --- README.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 6faaa80..4c01eb6 100644 --- a/README.rst +++ b/README.rst @@ -66,14 +66,11 @@ Documentation API documentation for this library can be found on `Read the Docs `_. +For information on building library documentation, please check out `this guide `_. + Contributing ============ Contributions are welcome! Please read our `Code of Conduct `_ before contributing to help this project stay welcoming. - -Documentation -============= - -For information on building library documentation, please check out `this guide `_. From af42f2d0836cc7e845c4ef069338e4761b81a77b Mon Sep 17 00:00:00 2001 From: dherrada Date: Mon, 14 Feb 2022 15:35:02 -0500 Subject: [PATCH 06/56] Fixed readthedocs build Signed-off-by: dherrada --- .readthedocs.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f8b2891..33c2a61 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,8 +8,12 @@ # Required version: 2 +build: + os: ubuntu-20.04 + tools: + python: "3" + python: - version: "3.x" install: - requirements: docs/requirements.txt - requirements: requirements.txt From a18fa639c6fcbf855899a81098df62dad0e95358 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Fri, 25 Mar 2022 17:10:21 -0400 Subject: [PATCH 07/56] Add type annotations to adafruit_fona.py --- adafruit_fona/adafruit_fona.py | 189 +++++++++++++++++++++------------ 1 file changed, 119 insertions(+), 70 deletions(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index 4a71c84..fa7ec15 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: MIT +# pylint: disable=too-many-lines + """ `adafruit_fona` ================================================================================ @@ -24,6 +26,14 @@ from micropython import const from simpleio import map_range +try: + from typing import Optional, Tuple + from circuitpython_typing import ReadableBuffer + from busio import UART + from digitalio import DigitalInOut +except ImportError: + pass + __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FONA.git" @@ -65,7 +75,13 @@ class FONA: UDP_MODE = const(1) # UDP socket # pylint: disable=too-many-arguments - def __init__(self, uart, rst, ri=None, debug=False): + def __init__( + self, + uart: UART, + rst: DigitalInOut, + ri: Optional[DigitalInOut] = None, + debug: bool = False, + ) -> None: self._buf = b"" # shared buffer self._fona_type = 0 self._debug = debug @@ -79,7 +95,7 @@ def __init__(self, uart, rst, ri=None, debug=False): raise RuntimeError("Unable to find FONA. Please check connections.") # pylint: disable=too-many-branches, too-many-statements - def _init_fona(self): + def _init_fona(self) -> bool: """Initializes FONA module.""" self.reset() @@ -136,7 +152,7 @@ def _init_fona(self): self._fona_type = FONA_800_H return True - def factory_reset(self): + def factory_reset(self) -> bool: """Resets modem to factory configuration.""" self._uart_write(b"ATZ\r\n") @@ -144,7 +160,7 @@ def factory_reset(self): return False return True - def reset(self): + def reset(self) -> None: """Performs a hardware reset on the modem.""" if self._debug: print("* Reset FONA") @@ -157,14 +173,14 @@ def reset(self): @property # pylint: disable=too-many-return-statements - def version(self): + def version(self) -> int: """The version of the FONA module. Can be FONA_800_L, FONA_800_H, FONA_808_V1, FONA_808_V2, FONA_3G_A, FONA3G_E. """ return self._fona_type @property - def iemi(self): + def iemi(self) -> str: """FONA Module's IEMI (International Mobile Equipment Identity) number.""" if self._debug: print("FONA IEMI") @@ -176,7 +192,7 @@ def iemi(self): return iemi.decode("utf-8") @property - def local_ip(self): + def local_ip(self) -> Optional[str]: """Module's local IP address, None if not set.""" self._uart_write(b"AT+CIFSR\r\n") self._read_line() @@ -187,7 +203,7 @@ def local_ip(self): return ip_addr @property - def iccid(self): + def iccid(self) -> str: """SIM Card's unique ICCID (Integrated Circuit Card Identifier).""" if self._debug: print("ICCID") @@ -197,7 +213,7 @@ def iccid(self): return iccid @property - def gprs(self): + def gprs(self) -> bool: """GPRS (General Packet Radio Services) power status.""" if not self._send_parse_reply(b"AT+CGATT?", b"+CGATT: ", ":"): return False @@ -206,10 +222,15 @@ def gprs(self): return True # pylint: disable=too-many-return-statements - def set_gprs(self, apn=None, enable=True): + def set_gprs( + self, + apn: Optional[Tuple[str, Optional[str], Optional[str]]] = None, + enable: bool = True, + ) -> bool: """Configures and brings up GPRS. - :param bool enable: Enables or disables GPRS. + :param tuple apn: The APN information + :param bool enable: Enables or disables GPRS. """ if enable: apn_name, apn_user, apn_pass = apn @@ -293,7 +314,7 @@ def set_gprs(self, apn=None, enable=True): return True @property - def network_status(self): + def network_status(self) -> int: """The status of the cellular network.""" self._read_line() if self._debug: @@ -306,7 +327,7 @@ def network_status(self): return status @property - def rssi(self): + def rssi(self) -> float: """The received signal strength indicator for the cellular network we are connected to. """ @@ -331,7 +352,7 @@ def rssi(self): return rssi @property - def gps(self): + def gps(self) -> int: """Module's GPS status.""" if self._debug: print("GPS Fix") @@ -354,7 +375,7 @@ def gps(self): return status @gps.setter - def gps(self, gps_on=False): + def gps(self, gps_on: bool = False) -> bool: if self._fona_type not in (FONA_3G_A, FONA_3G_E, FONA_808_V1, FONA_808_V2): raise TypeError("GPS unsupported for this FONA module.") @@ -385,11 +406,15 @@ def gps(self, gps_on=False): return True - def pretty_ip(self, ip): # pylint: disable=no-self-use, invalid-name + def pretty_ip( # pylint: disable=no-self-use, invalid-name + self, ip: ReadableBuffer + ) -> str: """Converts a bytearray IP address to a dotted-quad string for printing""" return "%d.%d.%d.%d" % (ip[0], ip[1], ip[2], ip[3]) - def unpretty_ip(self, ip): # pylint: disable=no-self-use, invalid-name + def unpretty_ip( # pylint: disable=no-self-use, invalid-name + self, ip: str + ) -> bytes: """Converts a dotted-quad string to a bytearray IP address""" octets = [int(x) for x in ip.split(".")] return bytes(octets) @@ -397,14 +422,14 @@ def unpretty_ip(self, ip): # pylint: disable=no-self-use, invalid-name ### SMS ### @property - def enable_sms_notification(self): + def enable_sms_notification(self) -> bool: """Checks if SMS notifications are enabled.""" if not self._send_parse_reply(b"AT+CNMI?\r\n", b"+CNMI:", idx=1): return False return self._buf @enable_sms_notification.setter - def enable_sms_notification(self, enable=True): + def enable_sms_notification(self, enable: bool = True) -> bool: if enable: if not self._send_check_reply(b"AT+CNMI=2,1\r\n", reply=REPLY_OK): return False @@ -413,9 +438,10 @@ def enable_sms_notification(self, enable=True): return False return True - def receive_sms(self): + def receive_sms(self) -> Tuple[str, str]: """Checks for a message notification from the FONA module, replies back with the a tuple containing (sender, message). + NOTE: This method needs to be polled consistently due to the lack of hw-based interrupts in CircuitPython. @@ -437,11 +463,11 @@ def receive_sms(self): return sender, message.strip() - def send_sms(self, phone_number, message): + def send_sms(self, phone_number: int, message: str) -> bool: """Sends a message SMS to a phone number. + :param int phone_number: Destination phone number. :param str message: Message to send to the phone number. - """ if not hasattr(phone_number, "to_bytes"): raise TypeError("Phone number must be integer") @@ -474,10 +500,10 @@ def send_sms(self, phone_number, message): return False return True - def num_sms(self, sim_storage=True): + def num_sms(self, sim_storage: bool = True) -> int: """Returns the number of SMS messages stored in memory. - :param bool sim_storage: SMS storage on the SIM, otherwise internal storage on FONA chip. + :param bool sim_storage: SMS storage on the SIM, otherwise internal storage on FONA chip. """ if not self._send_check_reply(b"AT+CMGF=1", reply=REPLY_OK): raise RuntimeError("Operating mode not supported by FONA module.") @@ -500,10 +526,10 @@ def num_sms(self, sim_storage=True): return self._buf return 0 - def delete_sms(self, sms_slot): + def delete_sms(self, sms_slot: int) -> bool: """Deletes a SMS message from a storage (internal or sim) slot - :param int sms_slot: SMS SIM or FONA memory slot number. + :param int sms_slot: SMS SIM or FONA memory slot number. """ if not self._send_check_reply(b"AT+CMGF=1", reply=REPLY_OK): return False @@ -515,7 +541,7 @@ def delete_sms(self, sms_slot): return True - def delete_all_sms(self): + def delete_all_sms(self) -> bool: """Deletes all SMS messages on the FONA SIM.""" self._read_line() if not self._send_check_reply(b"AT+CMGF=1", reply=REPLY_OK): @@ -533,11 +559,11 @@ def delete_all_sms(self): return False return True - def read_sms(self, sms_slot): + def read_sms(self, sms_slot: int) -> Tuple[str, str]: """Reads and parses SMS messages from FONA device. Returns the SMS sender's phone number and the message contents as a tuple. - :param int sms_slot: SMS SIM or FONA memory slot number. + :param int sms_slot: SMS SIM or FONA memory slot number. """ if not self._send_check_reply(b"AT+CMGF=1", reply=REPLY_OK): return False @@ -569,10 +595,10 @@ def read_sms(self, sms_slot): ### Socket API (TCP, UDP) ### - def get_host_by_name(self, hostname): + def get_host_by_name(self, hostname: str) -> bytes: """Converts a hostname to a packed 4-byte IP address. - :param str hostname: Destination server. + :param str hostname: Destination server. """ self._read_line() if self._debug: @@ -590,7 +616,7 @@ def get_host_by_name(self, hostname): self._read_line() return self._buf - def get_socket(self): + def get_socket(self) -> int: """Obtains a socket, if available.""" if self._debug: print("*** Get socket") @@ -613,10 +639,10 @@ def get_socket(self): print("Allocated socket #%d" % allocated_socket) return allocated_socket - def remote_ip(self, sock_num): + def remote_ip(self, sock_num: int) -> str: """Returns the IP address of the remote server. - :param int sock_num: Desired socket. + :param int sock_num: Desired socket. """ assert ( sock_num < FONA_MAX_SOCKETS @@ -628,10 +654,10 @@ def remote_ip(self, sock_num): self._parse_reply(b"+CIPSTATUS:", idx=3) return self._buf - def socket_status(self, sock_num): + def socket_status(self, sock_num: int) -> bool: """Returns the socket connection status, False if not connected. - :param int sock_num: Desired socket number. + :param int sock_num: Desired socket number. """ assert ( sock_num < FONA_MAX_SOCKETS @@ -658,10 +684,10 @@ def socket_status(self, sock_num): return True - def socket_available(self, sock_num): + def socket_available(self, sock_num: int) -> int: """Returns the amount of bytes available to be read from the socket. - :param int sock_num: Desired socket to return bytes available from. + :param int sock_num: Desired socket to return bytes available from. """ assert ( sock_num < FONA_MAX_SOCKETS @@ -681,14 +707,16 @@ def socket_available(self, sock_num): return data - def socket_connect(self, sock_num, dest, port, conn_mode=TCP_MODE): + def socket_connect( + self, sock_num: int, dest: str, port: int, conn_mode: int = TCP_MODE + ) -> bool: """Connects to a destination IP address or hostname. By default, we use conn_mode TCP_MODE but we may also use UDP_MODE. + :param int sock_num: Desired socket number :param str dest: Destination dest address. :param int port: Destination dest port. :param int conn_mode: Connection mode (TCP/UDP) - """ if self._debug: print( @@ -722,10 +750,10 @@ def socket_connect(self, sock_num, dest, port, conn_mode=TCP_MODE): return False return True - def socket_close(self, sock_num): + def socket_close(self, sock_num: int) -> bool: """Close TCP or UDP connection - :param int sock_num: Desired socket number. + :param int sock_num: Desired socket number. """ if self._debug: print("*** Closing socket #%d" % sock_num) @@ -745,12 +773,12 @@ def socket_close(self, sock_num): return False return True - def socket_read(self, sock_num, length): + def socket_read(self, sock_num: int, length: int) -> bytearray: """Read data from the network into a buffer. - Returns buffer and amount of bytes read. + Returns bytes read. + :param int sock_num: Desired socket to read from. :param int length: Desired length to read. - """ self._read_line() assert ( @@ -769,12 +797,12 @@ def socket_read(self, sock_num, length): return self._uart.read(length) - def socket_write(self, sock_num, buffer, timeout=3000): + def socket_write(self, sock_num: int, buffer: bytes, timeout: int = 3000) -> bool: """Writes bytes to the socket. + :param int sock_num: Desired socket number to write to. :param bytes buffer: Bytes to write to socket. :param int timeout: Socket write timeout, in milliseconds. - """ self._read_line() assert ( @@ -801,18 +829,21 @@ def socket_write(self, sock_num, buffer, timeout=3000): ### UART Reply/Response Helpers ### - def _uart_write(self, buffer): + def _uart_write(self, buffer: bytes) -> None: """UART ``write`` with optional debug that prints the buffer before sending. - :param bytes buffer: Buffer of bytes to send to the bus. + :param bytes buffer: Buffer of bytes to send to the bus. """ if self._debug: print("\tUARTWRITE ::", buffer.decode()) self._uart.write(buffer) - def _send_parse_reply(self, send_data, reply_data, divider=",", idx=0): + def _send_parse_reply( + self, send_data: bytes, reply_data: bytes, divider: str = ",", idx: int = 0 + ) -> bool: """Sends data to FONA module, parses reply data returned. + :param bytes send_data: Data to send to the module. :param bytes send_data: Data received by the FONA module. :param str divider: Separator @@ -826,12 +857,18 @@ def _send_parse_reply(self, send_data, reply_data, divider=",", idx=0): return True def _get_reply( - self, data=None, prefix=None, suffix=None, timeout=FONA_DEFAULT_TIMEOUT_MS - ): + self, + data: Optional[bytes] = None, + prefix: Optional[bytes] = None, + suffix: Optional[bytes] = None, + timeout: int = FONA_DEFAULT_TIMEOUT_MS, + ) -> Tuple[int, bytes]: """Send data to FONA, read response into buffer. + :param bytes data: Data to send to FONA module. + :param bytes prefix: Data to write if ``data`` is not provided + :param bytes suffix: Data to write following ``prefix`` if ``data is not provided :param int timeout: Time to wait for UART response. - """ self._uart.reset_input_buffer() @@ -842,11 +879,11 @@ def _get_reply( return self._read_line(timeout) - def _parse_reply(self, reply, divider=",", idx=0): + def _parse_reply(self, reply: bytes, divider: str = ",", idx: int = 0) -> bool: """Attempts to find reply in UART buffer, reads up to divider. + :param bytes reply: Expected response from FONA module. :param str divider: Divider character. - """ parsed_reply = self._buf.find(reply) if parsed_reply == -1: @@ -866,12 +903,14 @@ def _parse_reply(self, reply, divider=",", idx=0): return True - def _read_line(self, timeout=FONA_DEFAULT_TIMEOUT_MS, multiline=False): + def _read_line( + self, timeout: int = FONA_DEFAULT_TIMEOUT_MS, multiline: bool = False + ) -> Tuple[int, bytes]: """Reads one or multiple lines into the buffer. Optionally prints the buffer after reading. + :param int timeout: Time to wait for UART serial to reply, in seconds. :param bool multiline: Read multiple lines. - """ self._buf = b"" reply_idx = 0 @@ -904,16 +943,19 @@ def _read_line(self, timeout=FONA_DEFAULT_TIMEOUT_MS, multiline=False): def _send_check_reply( self, - send=None, - prefix=None, - suffix=None, - reply=None, + send: Optional[bytes] = None, + prefix: Optional[bytes] = None, + suffix: Optional[bytes] = None, + reply: Optional[bytes] = None, timeout=FONA_DEFAULT_TIMEOUT_MS, - ): + ) -> bool: """Sends data to FONA, validates response. + :param bytes send: Command. + :param bytes prefix: Data to send if ``send`` not provided + :param bytes suffix: Data to send after ``prefix`` if ``send`` not provided :param bytes reply: Expected response from module. - + :param int timeout: Time to wait for UART serial to reply, in seconds. """ self._read_line() if send is None: @@ -929,14 +971,18 @@ def _send_check_reply( return True def _send_check_reply_quoted( - self, prefix, suffix, reply, timeout=FONA_DEFAULT_TIMEOUT_MS - ): + self, + prefix: bytes, + suffix: bytes, + reply: bytes, + timeout: int = FONA_DEFAULT_TIMEOUT_MS, + ) -> bool: """Send prefix, ", suffix, ", and a newline. Verify response against reply. + :param bytes prefix: Command prefix. :param bytes prefix: Command ", suffix, ". :param bytes reply: Expected response from module. :param int timeout: Time to expect reply back from FONA, in milliseconds. - """ self._buf = b"" @@ -946,13 +992,15 @@ def _send_check_reply_quoted( return False return True - def _get_reply_quoted(self, prefix, suffix, timeout): + def _get_reply_quoted( + self, prefix: bytes, suffix: bytes, timeout: int + ) -> Tuple[int, bytes]: """Send prefix, ", suffix, ", and newline. Returns: Response (and also fills buffer with response). + :param bytes prefix: Command prefix. :param bytes prefix: Command ", suffix, ". :param int timeout: Time to expect reply back from FONA, in milliseconds. - """ self._uart.reset_input_buffer() @@ -960,10 +1008,11 @@ def _get_reply_quoted(self, prefix, suffix, timeout): return self._read_line(timeout) - def _expect_reply(self, reply, timeout=10000): + def _expect_reply(self, reply: bytes, timeout: int = 10000) -> bool: """Reads line from FONA module and compares to reply from FONA module. - :param bytes reply: Expected reply from module. + :param bytes reply: Expected reply from module. + :param int timeout: Time to wait for UART serial to reply, in seconds. """ self._read_line(timeout) if reply not in self._buf: From 7faf9d66007f4750e7116f91fd9320bbada2df3a Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Fri, 25 Mar 2022 17:16:50 -0400 Subject: [PATCH 08/56] Add type annotations to adafruit_fona_network.py --- adafruit_fona/adafruit_fona_network.py | 37 +++++++++++++++++++------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/adafruit_fona/adafruit_fona_network.py b/adafruit_fona/adafruit_fona_network.py index fd79183..30cf38a 100755 --- a/adafruit_fona/adafruit_fona_network.py +++ b/adafruit_fona/adafruit_fona_network.py @@ -12,6 +12,16 @@ """ +try: + from typing import Optional, Tuple, Type + from types import TracebackType + from adafruit_fona.adafruit_fona import FONA +except ImportError: + pass + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FONA.git" + # Network types NET_GSM = 0x01 NET_CDMA = 0x02 @@ -20,12 +30,14 @@ class CELLULAR: """Interface for connecting to and interacting with GSM and CDMA cellular networks.""" - def __init__(self, fona, apn): + def __init__( + self, fona: FONA, apn: Tuple[str, Optional[str], Optional[str]] + ) -> None: """Initializes interface with cellular network. - :param adafruit_fona fona: The Adafruit FONA module we are using. + + :param FONA fona: The Adafruit FONA module we are using. :param tuple apn: Tuple containing APN name, (optional) APN username, and APN password. - """ self._iface = fona self._apn = apn @@ -36,24 +48,29 @@ def __init__(self, fona, apn): self._network_type = NET_GSM self._iface.gps = True - def __enter__(self): + def __enter__(self) -> "CELLULAR": return self - def __exit__(self, exception_type, exception_value, traceback): + def __exit__( + self, + exception_type: Optional[Type[type]], + exception_value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: self.disconnect() @property - def imei(self): + def imei(self) -> str: """Returns the modem's IEMI number, as a string.""" return self._iface.iemi @property - def iccid(self): + def iccid(self) -> str: """Returns the SIM card's ICCID, as a string.""" return self._iface.iccid @property - def is_attached(self): + def is_attached(self) -> bool: """Returns if the modem is attached to the network.""" if self._network_type == NET_GSM: if self._iface.gps == 3 and self._iface.network_status == 1: @@ -70,7 +87,7 @@ def is_connected(self): return False return True - def connect(self): + def connect(self) -> None: """Connect to cellular network.""" if self._iface.set_gprs(self._apn, True): self._network_connected = True @@ -78,7 +95,7 @@ def connect(self): # reset context for next connection attempt self._iface.set_gprs(self._apn, False) - def disconnect(self): + def disconnect(self) -> None: """Disconnect from cellular network.""" self._iface.set_gprs(self._apn, False) self._network_connected = False From a243db100911f246ea95c717e17c78d62bc7284b Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Fri, 25 Mar 2022 17:39:55 -0400 Subject: [PATCH 09/56] Correct type annotation for get_host_be_name() --- adafruit_fona/adafruit_fona.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index fa7ec15..aaef49b 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -595,7 +595,7 @@ def read_sms(self, sms_slot: int) -> Tuple[str, str]: ### Socket API (TCP, UDP) ### - def get_host_by_name(self, hostname: str) -> bytes: + def get_host_by_name(self, hostname: str) -> str: """Converts a hostname to a packed 4-byte IP address. :param str hostname: Destination server. From d2bafae75923e889f877f5140b860aa68334f8e2 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Fri, 25 Mar 2022 17:40:11 -0400 Subject: [PATCH 10/56] Add type annotations to adafruit_fona_socket.py --- adafruit_fona/adafruit_fona_socket.py | 64 ++++++++++++++++----------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/adafruit_fona/adafruit_fona_socket.py b/adafruit_fona/adafruit_fona_socket.py index 16034e6..041d626 100644 --- a/adafruit_fona/adafruit_fona_socket.py +++ b/adafruit_fona/adafruit_fona_socket.py @@ -16,16 +16,22 @@ import time from micropython import const +try: + from typing import Optional, Tuple, Sequence + from adafruit_fona.adafruit_fona import FONA +except ImportError: + pass + _the_interface = None # pylint: disable=invalid-name -def set_interface(iface): +def set_interface(iface: FONA) -> None: """Helper to set the global internet interface.""" global _the_interface # pylint: disable=global-statement, invalid-name _the_interface = iface -def htonl(x): +def htonl(x: int) -> int: """Convert 32-bit positive integers from host to network byte order.""" return ( ((x) << 24 & 0xFF000000) @@ -35,7 +41,7 @@ def htonl(x): ) -def htons(x): +def htons(x: int) -> int: """Convert 16-bit positive integers from host to network byte order.""" return (((x) << 8) & 0xFF00) | (((x) >> 8) & 0xFF) @@ -50,7 +56,7 @@ def htons(x): SOCKETS = [] # pylint: disable=too-many-arguments, unused-argument -def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0): +def getaddrinfo(host, port: int, family=0, socktype=0, proto=0, flags=0): """Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. """ @@ -59,9 +65,10 @@ def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0): return [(AF_INET, socktype, proto, "", (gethostbyname(host), port))] -def gethostbyname(hostname): +def gethostbyname(hostname: str) -> str: """Translate a host name to IPv4 address format. The IPv4 address is returned as a string. + :param str hostname: Desired hostname. """ addr = _the_interface.get_host_by_name(hostname) @@ -72,14 +79,19 @@ def gethostbyname(hostname): class socket: """A simplified implementation of the Python 'socket' class for connecting to a FONA cellular module. + :param int family: Socket address (and protocol) family. :param int type: Socket type. - """ def __init__( - self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, socknum=None - ): + self, + family: int = AF_INET, + type: int = SOCK_STREAM, + proto: int = 0, + fileno: Optional[int] = None, + socknum: Optional[int] = None, + ) -> None: if family != AF_INET: raise RuntimeError("Only AF_INET family supported by cellular sockets.") self._sock_type = type @@ -94,35 +106,37 @@ def __init__( self.settimeout(self._timeout) @property - def socknum(self): + def socknum(self) -> int: """Returns the socket object's socket number.""" return self._socknum @property - def connected(self): + def connected(self) -> bool: """Returns whether or not we are connected to the socket.""" return _the_interface.socket_status(self.socknum) - def getpeername(self): + def getpeername(self) -> str: """Return the remote address to which the socket is connected.""" return _the_interface.remote_ip(self.socknum) - def inet_aton(self, ip_string): + def inet_aton(self, ip_string: str) -> bytearray: """Convert an IPv4 address from dotted-quad string format. - :param str ip_string: IP Address, as a dotted-quad string. + :param str ip_string: IP Address, as a dotted-quad string. """ self._buffer = b"" self._buffer = [int(item) for item in ip_string.split(".")] self._buffer = bytearray(self._buffer) return self._buffer - def connect(self, address, conn_mode=None): + def connect( + self, address: Tuple[str, int], conn_mode: Optional[int] = None + ) -> None: """Connect to a remote socket at address. (The format of address depends on the address family — see above.) + :param tuple address: Remote socket as a (host, port) tuple. :param int conn_mode: Connection mode (TCP/UDP) - """ assert ( conn_mode != 0x03 @@ -135,17 +149,18 @@ def connect(self, address, conn_mode=None): raise RuntimeError("Failed to connect to host", host) self._buffer = b"" - def send(self, data): + def send(self, data: bytes) -> None: """Send data to the socket. The socket must be connected to a remote socket prior to calling this method. - :param bytes data: Desired data to send to the socket. + :param bytes data: Desired data to send to the socket. """ _the_interface.socket_write(self._socknum, data, self._timeout) gc.collect() - def recv(self, bufsize=0): + def recv(self, bufsize: int = 0) -> Sequence[int]: """Reads some bytes from the connected remote address. + :param int bufsize: maximum number of bytes to receive """ # print("Socket read", bufsize) @@ -189,7 +204,7 @@ def recv(self, bufsize=0): gc.collect() return ret - def readline(self): + def readline(self) -> Sequence[int]: """Attempt to return as many bytes as we can up to but not including '\r\n'""" # print("Socket readline") stamp = time.monotonic() @@ -205,26 +220,25 @@ def readline(self): gc.collect() return firstline - def available(self): + def available(self) -> int: """Returns how many bytes are available to be read from the socket.""" return _the_interface.socket_available(self._socknum) - def settimeout(self, value): + def settimeout(self, value: int) -> None: """Sets socket read timeout. - :param int value: Socket read timeout, in seconds. + :param int value: Socket read timeout, in seconds. """ if value < 0: raise Exception("Timeout period should be non-negative.") self._timeout = value - def gettimeout(self): + def gettimeout(self) -> int: """Return the timeout in seconds (float) associated with socket operations, or None if no timeout is set. - """ return self._timeout - def close(self): + def close(self) -> bool: """Closes the socket.""" return _the_interface.socket_close(self._socknum) From 9b8fb8bf582c19ff2c5958aabd36b000c65e4a35 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Fri, 25 Mar 2022 17:51:52 -0400 Subject: [PATCH 11/56] Update type annotations for get_host_by_name() --- adafruit_fona/adafruit_fona.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index aaef49b..1e88937 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -27,7 +27,7 @@ from simpleio import map_range try: - from typing import Optional, Tuple + from typing import Optional, Tuple, Union, Literal from circuitpython_typing import ReadableBuffer from busio import UART from digitalio import DigitalInOut @@ -595,7 +595,7 @@ def read_sms(self, sms_slot: int) -> Tuple[str, str]: ### Socket API (TCP, UDP) ### - def get_host_by_name(self, hostname: str) -> str: + def get_host_by_name(self, hostname: str) -> Union[str, Literal[False]]: """Converts a hostname to a packed 4-byte IP address. :param str hostname: Destination server. @@ -847,7 +847,6 @@ def _send_parse_reply( :param bytes send_data: Data to send to the module. :param bytes send_data: Data received by the FONA module. :param str divider: Separator - """ self._read_line() self._get_reply(send_data) From 8cfabc3d0d68b70f5625357e1aa1e49bad5758ae Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Fri, 25 Mar 2022 17:52:06 -0400 Subject: [PATCH 12/56] Add type annotations for fona_3g.py --- adafruit_fona/fona_3g.py | 72 ++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/adafruit_fona/fona_3g.py b/adafruit_fona/fona_3g.py index a16c9d3..c9acce5 100755 --- a/adafruit_fona/fona_3g.py +++ b/adafruit_fona/fona_3g.py @@ -24,6 +24,13 @@ from micropython import const from .adafruit_fona import FONA, REPLY_OK +try: + from typing import Optional, Tuple, Union, Literal + from busio import UART + from digitalio import DigitalInOut +except ImportError: + pass + __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FONA.git" @@ -32,18 +39,24 @@ class FONA3G(FONA): """FONA 3G module interface. - :param ~busio.uart UART: FONA UART connection. - :param ~digialio RST: FONA RST pin. - :param ~digialio RI: Optional FONA Ring Interrupt (RI) pin. - :param bool debug: Enable debugging output. + :param ~busio.uart uart: FONA UART connection. + :param ~DigitalInOut rst: FONA RST pin. + :param ~DigitalInOut ri: Optional FONA Ring Interrupt (RI) pin. + :param bool debug: Enable debugging output. """ - def __init__(self, uart, rst, ri=None, debug=False): + def __init__( + self, + uart: UART, + rst: DigitalInOut, + ri: Optional[DigitalInOut] = None, + debug: bool = False, + ) -> None: uart.baudrate = 4800 super().__init__(uart, rst, ri, debug) - def set_baudrate(self, baudrate): + def set_baudrate(self, baudrate: int) -> bool: """Sets the FONA's UART baudrate.""" if not self._send_check_reply( b"AT+IPREX=" + str(baudrate).encode(), reply=REPLY_OK @@ -52,14 +65,14 @@ def set_baudrate(self, baudrate): return True @property - def gps(self): + def gps(self) -> bool: """Module's GPS status.""" if not self._send_check_reply(b"AT+CGPS?", reply=b"+CGPS: 1,1"): return False return True @gps.setter - def gps(self, gps_on=False): + def gps(self, gps_on: bool = False) -> bool: # check if GPS is already enabled if not self._send_parse_reply(b"AT+CGPS?", b"+CGPS: "): return False @@ -77,7 +90,7 @@ def gps(self, gps_on=False): return True @property - def ue_system_info(self): + def ue_system_info(self) -> bool: """UE System status.""" self._send_parse_reply(b"AT+CPSI?\r\n", b"+CPSI: ") if not self._buf == "GSM" or self._buf == "WCDMA": # 5.15 @@ -85,17 +98,22 @@ def ue_system_info(self): return True @property - def local_ip(self): + def local_ip(self) -> Optional[str]: """Module's local IP address, None if not set.""" if not self._send_parse_reply(b"AT+IPADDR", b"+IPADDR:"): return None return self._buf # pylint: disable=too-many-return-statements - def set_gprs(self, apn=None, enable=True): + def set_gprs( + self, + apn: Optional[Tuple[str, Optional[str], Optional[str]]] = None, + enable: bool = True, + ) -> bool: """Configures and brings up GPRS. - :param bool enable: Enables or disables GPRS. + :param tuple apn: APN configuration settings + :param bool enable: Enables or disables GPRS. """ if enable: if not self._send_check_reply(b"AT+CGATT=1", reply=REPLY_OK, timeout=10000): @@ -142,7 +160,7 @@ def set_gprs(self, apn=None, enable=True): ### Socket API (TCP, UDP) ### @property - def tx_timeout(self): + def tx_timeout(self) -> bool: """CIPSEND timeout, in milliseconds.""" self._read_line() if not self._send_parse_reply(b"AT+CIPTIMEOUT?", b"+CIPTIMEOUT:", idx=2): @@ -150,7 +168,7 @@ def tx_timeout(self): return True @tx_timeout.setter - def tx_timeout(self, timeout): + def tx_timeout(self, timeout: int) -> bool: self._read_line() if not self._send_check_reply( b"AT+CIPTIMEOUT=" + str(timeout).encode(), reply=REPLY_OK @@ -158,8 +176,9 @@ def tx_timeout(self, timeout): return False return True - def get_host_by_name(self, hostname): + def get_host_by_name(self, hostname: str) -> Union[str, Literal[False]]: """Converts a hostname to a 4-byte IP address. + :param str hostname: Domain name. """ self._read_line() @@ -175,7 +194,7 @@ def get_host_by_name(self, hostname): return False return self._buf - def get_socket(self): + def get_socket(self) -> int: """Returns an unused socket.""" if self._debug: print("*** Get socket") @@ -198,14 +217,16 @@ def get_socket(self): print("Allocated socket #%d" % socket) return socket - def socket_connect(self, sock_num, dest, port, conn_mode=0): + def socket_connect( + self, sock_num: int, dest: str, port: int, conn_mode: int = 0 + ) -> bool: """Connects to a destination IP address or hostname. By default, we use conn_mode TCP_MODE but we may also use UDP_MODE. + :param int sock_num: Desired socket number :param str dest: Destination dest address. :param int port: Destination dest port. :param int conn_mode: Connection mode (TCP/UDP) - """ if self._debug: print( @@ -236,8 +257,11 @@ def socket_connect(self, sock_num, dest, port, conn_mode=0): return False return True - def remote_ip(self, sock_num): - """Returns the IP address of the remote connection.""" + def remote_ip(self, sock_num: int) -> str: + """Returns the IP address of the remote connection. + + :param int sock_num: Desired socket number + """ self._read_line() assert ( sock_num < FONA_MAX_SOCKETS @@ -254,12 +278,12 @@ def remote_ip(self, sock_num): self._read_line() # eat the rest of '+CIPOPEN' responses return ip_addr - def socket_write(self, sock_num, buffer, timeout=120000): + def socket_write(self, sock_num: int, buffer: bytes, timeout: int = 120000) -> bool: """Writes len(buffer) bytes to the socket. + :param int sock_num: Desired socket number to write to. :param bytes buffer: Bytes to write to socket. :param int timeout: Socket write timeout, in milliseconds. Defaults to 120000ms. - """ self._read_line() assert ( @@ -295,10 +319,10 @@ def socket_write(self, sock_num, buffer, timeout=120000): return False return True - def socket_status(self, sock_num): + def socket_status(self, sock_num: int) -> bool: """Returns socket status, True if connected. False otherwise. - :param int sock_num: Desired socket number. + :param int sock_num: Desired socket number. """ if not self._send_parse_reply(b"AT+CIPCLOSE?", b"+CIPCLOSE:", idx=sock_num): return False From 1df5ee963febf49913e1a39bf6a4c812bffe1047 Mon Sep 17 00:00:00 2001 From: Neradoc Date: Mon, 28 Mar 2022 19:04:32 +0200 Subject: [PATCH 13/56] Fix documentation --- adafruit_fona/adafruit_fona.py | 13 ++++++------- adafruit_fona/adafruit_fona_network.py | 13 ++++++------- adafruit_fona/fona_3g.py | 9 ++++----- docs/api.rst | 6 ++++++ 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index 1e88937..fc838fa 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -64,11 +64,11 @@ # pylint: disable=too-many-instance-attributes, too-many-public-methods class FONA: """CircuitPython FONA module interface. - :param ~busio.uart UART: FONA UART connection. - :param ~digialio RST: FONA RST pin. - :param ~digialio RI: Optional FONA Ring Interrupt (RI) pin. - :param bool debug: Enable debugging output. + :param ~busio.UART uart: FONA UART connection. + :param ~digitalio.DigitalInOut rdt: FONA RST pin. + :param ~digitalio.DigitalInOut ri: Optional FONA Ring Interrupt (RI) pin. + :param bool debug: Enable debugging output. """ TCP_MODE = const(0) # TCP socket @@ -442,9 +442,8 @@ def receive_sms(self) -> Tuple[str, str]: """Checks for a message notification from the FONA module, replies back with the a tuple containing (sender, message). - NOTE: This method needs to be polled consistently due to the lack - of hw-based interrupts in CircuitPython. - + :note: This method needs to be polled consistently due to the lack + of hw-based interrupts in CircuitPython. """ if self._ri is not None: # poll the RI pin if self._ri.value: diff --git a/adafruit_fona/adafruit_fona_network.py b/adafruit_fona/adafruit_fona_network.py index 30cf38a..c002f7d 100755 --- a/adafruit_fona/adafruit_fona_network.py +++ b/adafruit_fona/adafruit_fona_network.py @@ -28,17 +28,16 @@ class CELLULAR: - """Interface for connecting to and interacting with GSM and CDMA cellular networks.""" + """Interface for connecting to and interacting with GSM and CDMA cellular networks. + + :param FONA fona: The Adafruit FONA module we are using. + :param tuple apn: Tuple containing APN name, (optional) APN username, + and APN password. + """ def __init__( self, fona: FONA, apn: Tuple[str, Optional[str], Optional[str]] ) -> None: - """Initializes interface with cellular network. - - :param FONA fona: The Adafruit FONA module we are using. - :param tuple apn: Tuple containing APN name, (optional) APN username, - and APN password. - """ self._iface = fona self._apn = apn self._network_connected = False diff --git a/adafruit_fona/fona_3g.py b/adafruit_fona/fona_3g.py index c9acce5..eedad3e 100755 --- a/adafruit_fona/fona_3g.py +++ b/adafruit_fona/fona_3g.py @@ -4,8 +4,7 @@ # SPDX-License-Identifier: MIT """ -:py:class:`~adafruit_fona.fona_3g.FONA3G` -`adafruit_fona_3g` +`fona_3g` ================================================================================ FONA3G cellular module instance. @@ -40,9 +39,9 @@ class FONA3G(FONA): """FONA 3G module interface. - :param ~busio.uart uart: FONA UART connection. - :param ~DigitalInOut rst: FONA RST pin. - :param ~DigitalInOut ri: Optional FONA Ring Interrupt (RI) pin. + :param ~busio.UART uart: FONA UART connection. + :param ~digitalio.DigitalInOut rst: FONA RST pin. + :param ~digitalio.DigitalInOut ri: Optional FONA Ring Interrupt (RI) pin. :param bool debug: Enable debugging output. """ diff --git a/docs/api.rst b/docs/api.rst index 280ec86..7846032 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -9,3 +9,9 @@ .. automodule:: adafruit_fona.adafruit_fona_socket :members: + +.. automodule:: adafruit_fona.adafruit_fona_network + :members: + +.. automodule:: adafruit_fona.fona_3g + :members: From eff9e3f2868af9d7500fa99fd9aa9f6dc2926f92 Mon Sep 17 00:00:00 2001 From: Kattni Rembor Date: Mon, 28 Mar 2022 15:52:04 -0400 Subject: [PATCH 14/56] Update Black to latest. Signed-off-by: Kattni Rembor --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43d1385..29230db 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: - repo: https://github.com/python/black - rev: 20.8b1 + rev: 22.3.0 hooks: - id: black - repo: https://github.com/fsfe/reuse-tool From d1eb8b9470232da0ca68e37021c52e76269b9589 Mon Sep 17 00:00:00 2001 From: Eva Herrada <33632497+evaherrada@users.noreply.github.com> Date: Thu, 21 Apr 2022 18:50:31 -0400 Subject: [PATCH 15/56] Update .gitignore --- .gitignore | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index a966824..544ec4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,47 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries # -# SPDX-License-Identifier: Unlicense +# SPDX-License-Identifier: MIT +# Do not include files and directories created by your personal work environment, such as the IDE +# you use, except for those already listed here. Pull requests including changes to this file will +# not be accepted. + +# This .gitignore file contains rules for files generated by working with CircuitPython libraries, +# including building Sphinx, testing with pip, and creating a virual environment, as well as the +# MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs. + +# If you find that there are files being generated on your machine that should not be included in +# your git commit, you should create a .gitignore_global file on your computer to include the +# files created by your personal setup. To do so, follow the two steps below. + +# First, create a file called .gitignore_global somewhere convenient for you, and add rules for +# the files you want to exclude from git commits. + +# Second, configure Git to use the exclude file for all Git repositories by running the +# following via commandline, replacing "path/to/your/" with the actual path to your newly created +# .gitignore_global file: +# git config --global core.excludesfile path/to/your/.gitignore_global + +# CircuitPython-specific files *.mpy -.idea + +# Python-specific files __pycache__ -_build *.pyc + +# Sphinx build-specific files +_build + +# This file results from running `pip -e install .` in a local repository +*.egg-info + +# Virtual environment-specific files .env -.python-version -build*/ -bundles + +# MacOS-specific files *.DS_Store -.eggs -dist -**/*.egg-info + +# IDE-specific files +.idea .vscode +*~ From 88cf41656ef98b8689fab13f461d9754f4ae1253 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Fri, 22 Apr 2022 15:58:41 -0400 Subject: [PATCH 16/56] Patch: Replaced discord badge image --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4c01eb6..87aab5b 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Introduction :target: https://docs.circuitpython.org/projects/fona/en/latest/ :alt: Documentation Status -.. image:: https://img.shields.io/discord/327254708534116352.svg +.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Bundle/blob/main/badges/adafruit_discord.svg :target: https://adafru.it/discord :alt: Discord From 0f3ed79bedd8c6341e6b3835a72c7ac4a3399fde Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 24 Apr 2022 13:51:40 -0500 Subject: [PATCH 17/56] change discord badge --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 87aab5b..446376e 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,7 @@ Introduction :target: https://docs.circuitpython.org/projects/fona/en/latest/ :alt: Documentation Status -.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Bundle/blob/main/badges/adafruit_discord.svg +.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg :target: https://adafru.it/discord :alt: Discord From 39b374c644e2d34996e77e1e9e6accff7617e604 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 15 May 2022 12:26:04 -0400 Subject: [PATCH 18/56] Patch .pre-commit-config.yaml --- .pre-commit-config.yaml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 29230db..0a91a11 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,40 +3,40 @@ # SPDX-License-Identifier: Unlicense repos: -- repo: https://github.com/python/black + - repo: https://github.com/python/black rev: 22.3.0 hooks: - - id: black -- repo: https://github.com/fsfe/reuse-tool - rev: v0.12.1 + - id: black + - repo: https://github.com/fsfe/reuse-tool + rev: v0.14.0 hooks: - - id: reuse -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.3.0 + - id: reuse + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 hooks: - - id: check-yaml - - id: end-of-file-fixer - - id: trailing-whitespace -- repo: https://github.com/pycqa/pylint + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/pycqa/pylint rev: v2.11.1 hooks: - - id: pylint + - id: pylint name: pylint (library code) types: [python] args: - --disable=consider-using-f-string,duplicate-code exclude: "^(docs/|examples/|tests/|setup.py$)" - - id: pylint + - id: pylint name: pylint (example code) description: Run pylint rules on "examples/*.py" files types: [python] files: "^examples/" args: - - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code - - id: pylint + - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code + - id: pylint name: pylint (test code) description: Run pylint rules on "tests/*.py" files types: [python] files: "^tests/" args: - - --disable=missing-docstring,consider-using-f-string,duplicate-code + - --disable=missing-docstring,consider-using-f-string,duplicate-code From c5b47322776eb288efaed47adf1cf31125d8473f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 19 May 2022 19:29:46 -0500 Subject: [PATCH 19/56] fallback for Literal python37 --- adafruit_fona/adafruit_fona.py | 7 ++++++- adafruit_fona/fona_3g.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index fc838fa..a51bfd5 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -27,10 +27,15 @@ from simpleio import map_range try: - from typing import Optional, Tuple, Union, Literal + from typing import Optional, Tuple, Union from circuitpython_typing import ReadableBuffer from busio import UART from digitalio import DigitalInOut + + try: + from typing import Literal + except ImportError: + from typing_extensions import Literal except ImportError: pass diff --git a/adafruit_fona/fona_3g.py b/adafruit_fona/fona_3g.py index eedad3e..5ebd1e5 100755 --- a/adafruit_fona/fona_3g.py +++ b/adafruit_fona/fona_3g.py @@ -24,9 +24,13 @@ from .adafruit_fona import FONA, REPLY_OK try: - from typing import Optional, Tuple, Union, Literal + from typing import Optional, Tuple, Union from busio import UART from digitalio import DigitalInOut + try: + from typing import Literal + except ImportError: + from typing_extensions import Literal except ImportError: pass From 3cc71d5117ec8da97b3633187149d1597cb5c13c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 19 May 2022 19:35:58 -0500 Subject: [PATCH 20/56] format --- adafruit_fona/fona_3g.py | 1 + 1 file changed, 1 insertion(+) diff --git a/adafruit_fona/fona_3g.py b/adafruit_fona/fona_3g.py index 5ebd1e5..9f03c1f 100755 --- a/adafruit_fona/fona_3g.py +++ b/adafruit_fona/fona_3g.py @@ -27,6 +27,7 @@ from typing import Optional, Tuple, Union from busio import UART from digitalio import DigitalInOut + try: from typing import Literal except ImportError: From e8330079236276c78c37fbc7d860028797432365 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 22 May 2022 00:18:55 -0400 Subject: [PATCH 21/56] Increase min lines similarity Signed-off-by: Alec Delaney --- .pylintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index cfd1c41..f006a4a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -252,7 +252,7 @@ ignore-docstrings=yes ignore-imports=yes # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=12 [BASIC] From e38c11e57ec6f46edd3a49ab637f995581188453 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 22 May 2022 00:18:23 -0400 Subject: [PATCH 22/56] Switch to inclusive terminology Signed-off-by: Alec Delaney --- .pylintrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pylintrc b/.pylintrc index f006a4a..f772971 100644 --- a/.pylintrc +++ b/.pylintrc @@ -9,11 +9,11 @@ # run arbitrary code extension-pkg-whitelist= -# Add files or directories to the blacklist. They should be base names, not +# Add files or directories to the ignore-list. They should be base names, not # paths. ignore=CVS -# Add files or directories matching the regex patterns to the blacklist. The +# Add files or directories matching the regex patterns to the ignore-list. The # regex matches against base names, not paths. ignore-patterns= From e2e6e53bf45f627a1a4ed68764a73f0a0f57e580 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Mon, 30 May 2022 14:25:04 -0400 Subject: [PATCH 23/56] Set language to "en" for documentation Signed-off-by: Alec Delaney --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index cda1c23..5066de6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,7 +64,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. From df2721d7cd58ce52e27f5108734fb38c8d1dfdd5 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Tue, 7 Jun 2022 15:34:22 -0400 Subject: [PATCH 24/56] Added cp.org link to index.rst --- docs/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index d27a218..eca939e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -32,7 +32,8 @@ Table of Contents .. toctree:: :caption: Other Links - Download + Download from GitHub + Download Library Bundle CircuitPython Reference Documentation CircuitPython Support Forum Discord Chat From 63440ae5873fe25314c3800e1257622476748fb9 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Tue, 21 Jun 2022 17:00:37 -0400 Subject: [PATCH 25/56] Removed duplicate-code from library pylint disable Signed-off-by: evaherrada --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a91a11..3343606 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: name: pylint (library code) types: [python] args: - - --disable=consider-using-f-string,duplicate-code + - --disable=consider-using-f-string exclude: "^(docs/|examples/|tests/|setup.py$)" - id: pylint name: pylint (example code) From 59589c7c31f5dfbc4737d15bdf05da5c02008520 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Fri, 22 Jul 2022 13:58:47 -0400 Subject: [PATCH 26/56] Changed .env to .venv in README.rst --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 446376e..4f8ebc5 100644 --- a/README.rst +++ b/README.rst @@ -52,8 +52,8 @@ To install in a virtual environment in your current project: .. code-block:: shell mkdir project-name && cd project-name - python3 -m venv .env - source .env/bin/activate + python3 -m venv .venv + source .venv/bin/activate pip3 install adafruit-circuitpython-fona Usage Example From 1b197000a01b7581a69945d6ed44a2d4e0bb823c Mon Sep 17 00:00:00 2001 From: Eva Herrada <33632497+evaherrada@users.noreply.github.com> Date: Tue, 26 Jul 2022 13:50:01 -0400 Subject: [PATCH 27/56] Fixed badge link --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4f8ebc5..79d502f 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ Introduction ============ -.. image:: https://readthedocs.org/projects/adafruit-circuitpython-fona/badge/?version=latest +.. image:: https://readthedocs.org/projects/fona/badge/?version=latest :target: https://docs.circuitpython.org/projects/fona/en/latest/ :alt: Documentation Status From 512899f2e17a06a63efc8be4d0d607e25f804a4a Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Mon, 8 Aug 2022 22:05:52 -0400 Subject: [PATCH 28/56] Switched to pyproject.toml --- .github/workflows/build.yml | 18 +++++++----- .github/workflows/release.yml | 17 ++++++----- optional_requirements.txt | 3 ++ pyproject.toml | 45 ++++++++++++++++++++++++++++ requirements.txt | 4 +-- setup.py | 55 ----------------------------------- 6 files changed, 70 insertions(+), 72 deletions(-) create mode 100644 optional_requirements.txt create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 474520d..22f6582 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,6 +47,8 @@ jobs: pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit - name: Library version run: git describe --dirty --always --tags + - name: Setup problem matchers + uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 - name: Pre-commit hooks run: | pre-commit run --all-files @@ -60,16 +62,16 @@ jobs: - name: Build docs working-directory: docs run: sphinx-build -E -W -b html . _build/html - - name: Check For setup.py + - name: Check For pyproject.toml id: need-pypi run: | - echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) + echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - name: Build Python package - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') run: | - pip install --upgrade setuptools wheel twine readme_renderer testresources - python setup.py sdist - python setup.py bdist_wheel --universal + pip install --upgrade build twine + for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do + sed -i -e "s/0.0.0-auto.0/1.2.3/" $file; + done; + python -m build twine check dist/* - - name: Setup problem matchers - uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a65e5de..d1b4f8d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,25 +61,28 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Check For setup.py + - name: Check For pyproject.toml id: need-pypi run: | - echo ::set-output name=setup-py::$( find . -wholename './setup.py' ) + echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - name: Set up Python - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install --upgrade build twine - name: Build and publish - if: contains(steps.need-pypi.outputs.setup-py, 'setup.py') + if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') env: TWINE_USERNAME: ${{ secrets.pypi_username }} TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | - python setup.py sdist + for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do + sed -i -e "s/0.0.0-auto.0/${{github.event.release.tag_name}}/" $file; + done; + python -m build twine upload dist/* diff --git a/optional_requirements.txt b/optional_requirements.txt new file mode 100644 index 0000000..d4e27c4 --- /dev/null +++ b/optional_requirements.txt @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7049c39 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: 2022 Alec Delaney for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +[build-system] +requires = [ + "setuptools", + "wheel", +] + +[project] +name = "adafruit-circuitpython-fona" +description = "CircuitPython library for the Adafruit FONAA" +version = "0.0.0-auto.0" +readme = "README.rst" +authors = [ + {name = "Adafruit Industries", email = "circuitpython@adafruit.com"} +] +urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_FONA"} +keywords = [ + "adafruit", + "blinka", + "circuitpython", + "micropython", + "fona", + "fona,", + "cellular", +] +license = {text = "MIT"} +classifiers = [ + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Embedded Systems", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", +] +dynamic = ["dependencies", "optional-dependencies"] + +[tool.setuptools] +packages = ["adafruit_fona"] + +[tool.setuptools.dynamic] +dependencies = {file = ["requirements.txt"]} +optional-dependencies = {optional = {file = ["optional_requirements.txt"]}} diff --git a/requirements.txt b/requirements.txt index 593c9d9..c8bf6e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries # # SPDX-License-Identifier: Unlicense Adafruit-Blinka -adafruit-circuitpython-busdevice adafruit-circuitpython-simpleio +adafruit-circuitpython-busdevice diff --git a/setup.py b/setup.py deleted file mode 100644 index 52a843c..0000000 --- a/setup.py +++ /dev/null @@ -1,55 +0,0 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -"""A setuptools based setup module. - -See: -https://packaging.python.org/en/latest/distributing.html -https://github.com/pypa/sampleproject -""" - -from setuptools import setup, find_packages - -# To use a consistent encoding -from codecs import open -from os import path - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, "README.rst"), encoding="utf-8") as f: - long_description = f.read() - -setup( - name="adafruit-circuitpython-fona", - use_scm_version=True, - setup_requires=["setuptools_scm"], - description="CircuitPython library for the Adafruit FONAA", - long_description=long_description, - long_description_content_type="text/x-rst", - # The project's main homepage. - url="https://github.com/adafruit/Adafruit_CircuitPython_FONA", - # Author details - author="Adafruit Industries", - author_email="circuitpython@adafruit.com", - install_requires=["Adafruit-Blinka", "adafruit-circuitpython-busdevice"], - # Choose your license - license="MIT", - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Topic :: Software Development :: Libraries", - "Topic :: System :: Hardware", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - ], - # What does your project relate to? - keywords="adafruit blinka circuitpython micropython fona fona, cellular", - # You can just specify the packages manually here if your project is - # simple. Or you can use find_packages(). - # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER, - # CHANGE `py_modules=['...']` TO `packages=['...']` - packages=["adafruit_fona"], -) From 0eeeafafb68d0777d5c1cb234027607e216b1496 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 9 Aug 2022 12:03:54 -0400 Subject: [PATCH 29/56] Add setuptools-scm to build system requirements Signed-off-by: Alec Delaney --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 7049c39..6f14576 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ requires = [ "setuptools", "wheel", + "setuptools-scm", ] [project] From 13db85eec13263f926c7cffd982f5126f523b921 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 16 Aug 2022 18:09:13 -0400 Subject: [PATCH 30/56] Update version string --- adafruit_fona/adafruit_fona.py | 2 +- adafruit_fona/adafruit_fona_network.py | 2 +- adafruit_fona/fona_3g.py | 2 +- pyproject.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index a51bfd5..4af6fbb 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -39,7 +39,7 @@ except ImportError: pass -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FONA.git" FONA_DEFAULT_TIMEOUT_MS = 500 # TODO: Check this against arduino... diff --git a/adafruit_fona/adafruit_fona_network.py b/adafruit_fona/adafruit_fona_network.py index c002f7d..f60fa56 100755 --- a/adafruit_fona/adafruit_fona_network.py +++ b/adafruit_fona/adafruit_fona_network.py @@ -19,7 +19,7 @@ except ImportError: pass -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FONA.git" # Network types diff --git a/adafruit_fona/fona_3g.py b/adafruit_fona/fona_3g.py index 9f03c1f..cd8c609 100755 --- a/adafruit_fona/fona_3g.py +++ b/adafruit_fona/fona_3g.py @@ -35,7 +35,7 @@ except ImportError: pass -__version__ = "0.0.0-auto.0" +__version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_FONA.git" FONA_MAX_SOCKETS = const(10) diff --git a/pyproject.toml b/pyproject.toml index 6f14576..a43b25e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ requires = [ [project] name = "adafruit-circuitpython-fona" description = "CircuitPython library for the Adafruit FONAA" -version = "0.0.0-auto.0" +version = "0.0.0+auto.0" readme = "README.rst" authors = [ {name = "Adafruit Industries", email = "circuitpython@adafruit.com"} From 5a08487dd8d0cc240c1f7945b294fd33ff1026c5 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 16 Aug 2022 21:09:13 -0400 Subject: [PATCH 31/56] Fix version strings in workflow files --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22f6582..cb2f60e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,7 +71,7 @@ jobs: run: | pip install --upgrade build twine for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0-auto.0/1.2.3/" $file; + sed -i -e "s/0.0.0+auto.0/1.2.3/" $file; done; python -m build twine check dist/* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1b4f8d..f3a0325 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,7 +82,7 @@ jobs: TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0-auto.0/${{github.event.release.tag_name}}/" $file; + sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" $file; done; python -m build twine upload dist/* From a81a24a86532da3191ccd59d56a9f17283365218 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Mon, 22 Aug 2022 21:36:30 -0400 Subject: [PATCH 32/56] Keep copyright up to date in documentation --- docs/conf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 5066de6..6859384 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,6 +6,7 @@ import os import sys +import datetime sys.path.insert(0, os.path.abspath("..")) @@ -47,7 +48,8 @@ # General information about the project. project = "Adafruit FONA Library" -copyright = "2020 Brent Rubell, ladyada" +current_year = str(datetime.datetime.now().year) +copyright = current_year + " Brent Rubell, ladyada" author = "Brent Rubell, ladyada" # The version info for the project you're documenting, acts as replacement for From 84a77e6e43900c0d9f6353460f8db2b7108f8b48 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Tue, 23 Aug 2022 17:26:20 -0400 Subject: [PATCH 33/56] Use year duration range for copyright attribution --- docs/conf.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 6859384..82d83e8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,8 +48,14 @@ # General information about the project. project = "Adafruit FONA Library" +creation_year = "2020" current_year = str(datetime.datetime.now().year) -copyright = current_year + " Brent Rubell, ladyada" +year_duration = ( + current_year + if current_year == creation_year + else creation_year + " - " + current_year +) +copyright = year_duration + " Brent Rubell, ladyada" author = "Brent Rubell, ladyada" # The version info for the project you're documenting, acts as replacement for From 3ff944f276653f822a405199e5d4c3a251264dbe Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 00:02:49 -0400 Subject: [PATCH 34/56] Switching to composite actions --- .github/workflows/build.yml | 67 +---------------------- .github/workflows/release.yml | 88 ------------------------------ .github/workflows/release_gh.yml | 14 +++++ .github/workflows/release_pypi.yml | 14 +++++ 4 files changed, 30 insertions(+), 153 deletions(-) delete mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/release_gh.yml create mode 100644 .github/workflows/release_pypi.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb2f60e..041a337 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,68 +10,5 @@ jobs: test: runs-on: ubuntu-latest steps: - - name: Dump GitHub context - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - run: echo "$GITHUB_CONTEXT" - - name: Translate Repo Name For Build Tools filename_prefix - id: repo-name - run: | - echo ::set-output name=repo-name::$( - echo ${{ github.repository }} | - awk -F '\/' '{ print tolower($2) }' | - tr '_' '-' - ) - - name: Set up Python 3.x - uses: actions/setup-python@v2 - with: - python-version: "3.x" - - name: Versions - run: | - python3 --version - - name: Checkout Current Repo - uses: actions/checkout@v1 - with: - submodules: true - - name: Checkout tools repo - uses: actions/checkout@v2 - with: - repository: adafruit/actions-ci-circuitpython-libs - path: actions-ci - - name: Install dependencies - # (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.) - run: | - source actions-ci/install.sh - - name: Pip install Sphinx, pre-commit - run: | - pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit - - name: Library version - run: git describe --dirty --always --tags - - name: Setup problem matchers - uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 - - name: Pre-commit hooks - run: | - pre-commit run --all-files - - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . - - name: Archive bundles - uses: actions/upload-artifact@v2 - with: - name: bundles - path: ${{ github.workspace }}/bundles/ - - name: Build docs - working-directory: docs - run: sphinx-build -E -W -b html . _build/html - - name: Check For pyproject.toml - id: need-pypi - run: | - echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - - name: Build Python package - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - run: | - pip install --upgrade build twine - for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0+auto.0/1.2.3/" $file; - done; - python -m build - twine check dist/* + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index f3a0325..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -name: Release Actions - -on: - release: - types: [published] - -jobs: - upload-release-assets: - runs-on: ubuntu-latest - steps: - - name: Dump GitHub context - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - run: echo "$GITHUB_CONTEXT" - - name: Translate Repo Name For Build Tools filename_prefix - id: repo-name - run: | - echo ::set-output name=repo-name::$( - echo ${{ github.repository }} | - awk -F '\/' '{ print tolower($2) }' | - tr '_' '-' - ) - - name: Set up Python 3.x - uses: actions/setup-python@v2 - with: - python-version: "3.x" - - name: Versions - run: | - python3 --version - - name: Checkout Current Repo - uses: actions/checkout@v1 - with: - submodules: true - - name: Checkout tools repo - uses: actions/checkout@v2 - with: - repository: adafruit/actions-ci-circuitpython-libs - path: actions-ci - - name: Install deps - run: | - source actions-ci/install.sh - - name: Build assets - run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . - - name: Upload Release Assets - # the 'official' actions version does not yet support dynamically - # supplying asset names to upload. @csexton's version chosen based on - # discussion in the issue below, as its the simplest to implement and - # allows for selecting files with a pattern. - # https://github.com/actions/upload-release-asset/issues/4 - #uses: actions/upload-release-asset@v1.0.1 - uses: csexton/release-asset-action@master - with: - pattern: "bundles/*" - github-token: ${{ secrets.GITHUB_TOKEN }} - - upload-pypi: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Check For pyproject.toml - id: need-pypi - run: | - echo ::set-output name=pyproject-toml::$( find . -wholename './pyproject.toml' ) - - name: Set up Python - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - uses: actions/setup-python@v2 - with: - python-version: '3.x' - - name: Install dependencies - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - run: | - python -m pip install --upgrade pip - pip install --upgrade build twine - - name: Build and publish - if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') - env: - TWINE_USERNAME: ${{ secrets.pypi_username }} - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: | - for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" $file; - done; - python -m build - twine upload dist/* diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml new file mode 100644 index 0000000..041a337 --- /dev/null +++ b/.github/workflows/release_gh.yml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Build CI + +on: [pull_request, push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml new file mode 100644 index 0000000..041a337 --- /dev/null +++ b/.github/workflows/release_pypi.yml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +name: Build CI + +on: [pull_request, push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Run Build CI workflow + uses: adafruit/workflows-circuitpython-libs/build@main From acc2f466c9088d53b73a2c6d58d4d8bc029e9214 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 00:46:59 -0400 Subject: [PATCH 35/56] Updated pylint version to 2.13.0 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3343606..4c43710 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.11.1 + rev: v2.13.0 hooks: - id: pylint name: pylint (library code) From 7d28c9c4dfd07a840c7317ebf94561e5a205e6d9 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 08:15:19 -0400 Subject: [PATCH 36/56] Update pylint to 2.15.5 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c43710..0e5fccc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.13.0 + rev: v2.15.5 hooks: - id: pylint name: pylint (library code) From f416a77190f41e180cd097149cd5737b88531cae Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 09:12:43 -0400 Subject: [PATCH 37/56] Fix release CI files --- .github/workflows/release_gh.yml | 14 +++++++++----- .github/workflows/release_pypi.yml | 15 ++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml index 041a337..b8aa8d6 100644 --- a/.github/workflows/release_gh.yml +++ b/.github/workflows/release_gh.yml @@ -2,13 +2,17 @@ # # SPDX-License-Identifier: MIT -name: Build CI +name: GitHub Release Actions -on: [pull_request, push] +on: + release: + types: [published] jobs: - test: + upload-release-assets: runs-on: ubuntu-latest steps: - - name: Run Build CI workflow - uses: adafruit/workflows-circuitpython-libs/build@main + - name: Run GitHub Release CI workflow + uses: adafruit/workflows-circuitpython-libs/release-gh@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml index 041a337..65775b7 100644 --- a/.github/workflows/release_pypi.yml +++ b/.github/workflows/release_pypi.yml @@ -2,13 +2,18 @@ # # SPDX-License-Identifier: MIT -name: Build CI +name: PyPI Release Actions -on: [pull_request, push] +on: + release: + types: [published] jobs: - test: + upload-release-assets: runs-on: ubuntu-latest steps: - - name: Run Build CI workflow - uses: adafruit/workflows-circuitpython-libs/build@main + - name: Run PyPI Release CI workflow + uses: adafruit/workflows-circuitpython-libs/release-pypi@main + with: + pypi-username: ${{ secrets.pypi_username }} + pypi-password: ${{ secrets.pypi_password }} From 7c9ee8d078536ade9aff2b63f4082ff92ef311d6 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Fri, 4 Nov 2022 18:34:32 -0400 Subject: [PATCH 38/56] Update .pylintrc for v2.15.5 --- .pylintrc | 45 ++++----------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/.pylintrc b/.pylintrc index f772971..40208c3 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: Unlicense @@ -26,7 +26,7 @@ jobs=1 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins= +load-plugins=pylint.extensions.no_self_use # Pickle collected data for later comparisons. persistent=yes @@ -54,8 +54,8 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call -disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation,unspecified-encoding +# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call +disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option @@ -225,12 +225,6 @@ max-line-length=100 # Maximum number of lines in a module max-module-lines=1000 -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no @@ -257,38 +251,22 @@ min-similarity-lines=12 [BASIC] -# Naming hint for argument names -argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct argument names argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ -# Naming hint for attribute names -attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct attribute names attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ -# Naming hint for class names -# class-name-hint=[A-Z_][a-zA-Z0-9]+$ -class-name-hint=[A-Z_][a-zA-Z0-9_]+$ - # Regular expression matching correct class names # class-rgx=[A-Z_][a-zA-Z0-9]+$ class-rgx=[A-Z_][a-zA-Z0-9_]+$ -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ @@ -296,9 +274,6 @@ const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # ones are exempt. docstring-min-length=-1 -# Naming hint for function names -function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct function names function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ @@ -309,21 +284,12 @@ good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ # Include a hint for the correct naming format with invalid-name include-naming-hint=no -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -# Naming hint for method names -method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct method names method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ @@ -339,9 +305,6 @@ no-docstring-rgx=^_ # to this list to register other decorators that produce valid properties. property-classes=abc.abstractproperty -# Naming hint for variable names -variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - # Regular expression matching correct variable names variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ From 82964a7641d9048e1c05b67bec930f412763b412 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Thu, 10 Nov 2022 13:49:52 -0500 Subject: [PATCH 39/56] fixed linting --- adafruit_fona/adafruit_fona.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index 4af6fbb..7819f10 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -84,7 +84,7 @@ def __init__( self, uart: UART, rst: DigitalInOut, - ri: Optional[DigitalInOut] = None, + ri: Optional[DigitalInOut] = None, # pylint: disable=invalid-name debug: bool = False, ) -> None: self._buf = b"" # shared buffer From 2e64109b90dd3c28227d3c355bbc06c71fafe350 Mon Sep 17 00:00:00 2001 From: evaherrada Date: Thu, 10 Nov 2022 14:08:19 -0500 Subject: [PATCH 40/56] ran black --- adafruit_fona/adafruit_fona.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index 7819f10..5ac2b39 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -84,7 +84,7 @@ def __init__( self, uart: UART, rst: DigitalInOut, - ri: Optional[DigitalInOut] = None, # pylint: disable=invalid-name + ri: Optional[DigitalInOut] = None, # pylint: disable=invalid-name debug: bool = False, ) -> None: self._buf = b"" # shared buffer From 1264e9178ebbb0bdec478bd5812b74c23245b47a Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Thu, 1 Sep 2022 20:16:31 -0400 Subject: [PATCH 41/56] Add .venv to .gitignore Signed-off-by: Alec Delaney <89490472+tekktrik@users.noreply.github.com> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 544ec4a..db3d538 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ _build # Virtual environment-specific files .env +.venv # MacOS-specific files *.DS_Store From b35c765251c7ac49f5487ffa450d9d46d66b7308 Mon Sep 17 00:00:00 2001 From: Ric Sapasap Date: Sat, 14 Jan 2023 08:02:41 +0800 Subject: [PATCH 42/56] Fix docstring typo Signed-off-by: Ric Sapasap --- adafruit_fona/adafruit_fona.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index 5ac2b39..a7efae4 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -71,7 +71,7 @@ class FONA: """CircuitPython FONA module interface. :param ~busio.UART uart: FONA UART connection. - :param ~digitalio.DigitalInOut rdt: FONA RST pin. + :param ~digitalio.DigitalInOut rst: FONA RST pin. :param ~digitalio.DigitalInOut ri: Optional FONA Ring Interrupt (RI) pin. :param bool debug: Enable debugging output. """ From da576d5e22efaf3fe3f1ce6f505dd420c122f255 Mon Sep 17 00:00:00 2001 From: Ric Sapasap Date: Sat, 14 Jan 2023 08:50:58 +0800 Subject: [PATCH 43/56] Fix enabling GPS for non-gps modules Signed-off-by: Ric Sapasap --- adafruit_fona/adafruit_fona.py | 15 +++++++++++---- adafruit_fona/adafruit_fona_network.py | 22 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index a7efae4..1f244c7 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -56,6 +56,7 @@ # FONA Versions FONA_800_L = const(0x01) FONA_800_H = const(0x6) +FONA_800_C = const(0x7) FONA_808_V1 = const(0x2) FONA_808_V2 = const(0x3) FONA_3G_A = const(0x4) @@ -147,14 +148,20 @@ def _init_fona(self) -> bool: self._fona_type = FONA_3G_A elif self._buf.find(b"SIMCOM_SIM5320E") != -1: self._fona_type = FONA_3G_E - - if self._fona_type == FONA_800_L: - # determine if SIM800H + elif self._buf.find(b"SIM800") != -1: self._uart_write(b"AT+GMM\r\n") self._read_line(multiline=True) if self._buf.find(b"SIM800H") != -1: self._fona_type = FONA_800_H + elif self._buf.find(b"SIM800L") != -1: + self._fona_type = FONA_800_L + elif self._buf.find(b"SIM800C") != -1: + self._fona_type = FONA_800_C + + if self._debug and self._fona_type == 0: + print(f"Unsupported module: {self._buf}") + return True def factory_reset(self) -> bool: @@ -366,7 +373,7 @@ def gps(self) -> int: # Instead just look for a fix and if found assume it's a 3D fix. self._get_reply(b"AT+CGNSINF") - if not b"+CGNSINF: " in self._buf: + if b"+CGNSINF: " not in self._buf: return False status = int(self._buf[10:11].decode("utf-8")) diff --git a/adafruit_fona/adafruit_fona_network.py b/adafruit_fona/adafruit_fona_network.py index f60fa56..5d71985 100755 --- a/adafruit_fona/adafruit_fona_network.py +++ b/adafruit_fona/adafruit_fona_network.py @@ -41,11 +41,18 @@ def __init__( self._iface = fona self._apn = apn self._network_connected = False - self._network_type = NET_CDMA + self._network_type = NET_GSM + self._has_gps = False - if not self._iface.version == 0x4 or self._iface.version == 0x5: - self._network_type = NET_GSM + # These are numbers defined in adafruit_fona FONA versions + # For some reason, we can't import them from the adafruit_fona file + + if self._iface.version in (0x4, 0x5): + self._network_type = NET_CDMA + + if self._iface.version in (0x2, 0x3, 0x4, 0x5): self._iface.gps = True + self._has_gps = True def __enter__(self) -> "CELLULAR": return self @@ -72,7 +79,14 @@ def iccid(self) -> str: def is_attached(self) -> bool: """Returns if the modem is attached to the network.""" if self._network_type == NET_GSM: - if self._iface.gps == 3 and self._iface.network_status == 1: + if ( + self._has_gps + and self._iface.gps == 3 + and self._iface.network_status == 1 + ): + return True + + if not self._has_gps and self._iface.network_status == 1: return True else: # Attach CDMA network if self._iface.ue_system_info == 1 and self._iface.network_status == 1: From 239f8e31b8795bab2aa91d194ef53a4ec3f8d9eb Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Thu, 19 Jan 2023 23:39:55 -0500 Subject: [PATCH 44/56] Add upload url to release action Signed-off-by: Alec Delaney <89490472+tekktrik@users.noreply.github.com> --- .github/workflows/release_gh.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml index b8aa8d6..9acec60 100644 --- a/.github/workflows/release_gh.yml +++ b/.github/workflows/release_gh.yml @@ -16,3 +16,4 @@ jobs: uses: adafruit/workflows-circuitpython-libs/release-gh@main with: github-token: ${{ secrets.GITHUB_TOKEN }} + upload-url: ${{ github.event.release.upload_url }} From 4a6b6dc2915128ff2ee63be8bd8ffba4359754a9 Mon Sep 17 00:00:00 2001 From: Tekktrik Date: Tue, 9 May 2023 20:26:25 -0400 Subject: [PATCH 45/56] Update pre-commit hooks Signed-off-by: Tekktrik --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e5fccc..70ade69 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,21 +4,21 @@ repos: - repo: https://github.com/python/black - rev: 22.3.0 + rev: 23.3.0 hooks: - id: black - repo: https://github.com/fsfe/reuse-tool - rev: v0.14.0 + rev: v1.1.2 hooks: - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.4.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.15.5 + rev: v2.17.4 hooks: - id: pylint name: pylint (library code) From bbb6e0e5fe88406e3aa362f7e50f65db0497c6ce Mon Sep 17 00:00:00 2001 From: Tekktrik Date: Wed, 10 May 2023 22:32:55 -0400 Subject: [PATCH 46/56] Run pre-commit --- adafruit_fona/adafruit_fona_socket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/adafruit_fona/adafruit_fona_socket.py b/adafruit_fona/adafruit_fona_socket.py index 041d626..7aa210b 100644 --- a/adafruit_fona/adafruit_fona_socket.py +++ b/adafruit_fona/adafruit_fona_socket.py @@ -55,6 +55,7 @@ def htons(x: int) -> int: # keep track of sockets we allocate SOCKETS = [] + # pylint: disable=too-many-arguments, unused-argument def getaddrinfo(host, port: int, family=0, socktype=0, proto=0, flags=0): """Translate the host/port argument into a sequence of 5-tuples that From fe1c1f85be84ec80677e68c6d671e52f58238130 Mon Sep 17 00:00:00 2001 From: Tekktrik Date: Thu, 11 May 2023 08:23:49 -0400 Subject: [PATCH 47/56] Linted per pre-commit --- adafruit_fona/adafruit_fona_socket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_fona/adafruit_fona_socket.py b/adafruit_fona/adafruit_fona_socket.py index 7aa210b..c20c518 100644 --- a/adafruit_fona/adafruit_fona_socket.py +++ b/adafruit_fona/adafruit_fona_socket.py @@ -231,7 +231,7 @@ def settimeout(self, value: int) -> None: :param int value: Socket read timeout, in seconds. """ if value < 0: - raise Exception("Timeout period should be non-negative.") + raise ValueError("Timeout period should be non-negative.") self._timeout = value def gettimeout(self) -> int: From 36c96a0ca6f45c57112d2626f1624a286e2a82ea Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Tue, 23 May 2023 23:47:52 -0400 Subject: [PATCH 48/56] Update .pylintrc, fix jQuery for docs --- .pylintrc | 2 +- docs/conf.py | 1 + docs/requirements.txt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 40208c3..f945e92 100644 --- a/.pylintrc +++ b/.pylintrc @@ -396,4 +396,4 @@ min-public-methods=1 # Exceptions that will emit a warning when being caught. Defaults to # "Exception" -overgeneral-exceptions=Exception +overgeneral-exceptions=builtins.Exception diff --git a/docs/conf.py b/docs/conf.py index 82d83e8..2346f49 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,7 @@ # ones. extensions = [ "sphinx.ext.autodoc", + "sphinxcontrib.jquery", "sphinx.ext.intersphinx", "sphinx.ext.napoleon", "sphinx.ext.todo", diff --git a/docs/requirements.txt b/docs/requirements.txt index 88e6733..797aa04 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,3 +3,4 @@ # SPDX-License-Identifier: Unlicense sphinx>=4.0.0 +sphinxcontrib-jquery From 32a49567c618ee31ba37f95635ce28bedc6866d9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 19 Sep 2023 18:31:21 -0500 Subject: [PATCH 49/56] fix rtd theme --- docs/conf.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2346f49..92e250b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -105,19 +105,10 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get("READTHEDOCS", None) == "True" - -if not on_rtd: # only import and set the theme if we're building docs locally - try: - import sphinx_rtd_theme - - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] - except: - html_theme = "default" - html_theme_path = ["."] -else: - html_theme_path = ["."] +import sphinx_rtd_theme + +html_theme = "sphinx_rtd_theme" +html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From e1c9c9063ab086dceb22fea22b84807cd47b8a23 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 4 Dec 2023 11:24:18 -0600 Subject: [PATCH 50/56] unpin sphinx and add sphinx-rtd-theme to docs reqs --- docs/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 797aa04..979f568 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,5 +2,6 @@ # # SPDX-License-Identifier: Unlicense -sphinx>=4.0.0 +sphinx sphinxcontrib-jquery +sphinx-rtd-theme From 43bc1e6f27d6ab2c6f9c19622775fb0d8a739c28 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Thu, 29 Feb 2024 21:17:57 -0800 Subject: [PATCH 51/56] Update legacy set_socket examples --- examples/fona_aio_post.py | 10 ++++++---- examples/fona_cheerlights.py | 10 ++++++---- examples/fona_simpletest.py | 10 ++++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/fona_aio_post.py b/examples/fona_aio_post.py index 8c7d780..97ca459 100644 --- a/examples/fona_aio_post.py +++ b/examples/fona_aio_post.py @@ -6,11 +6,12 @@ import board import busio import digitalio -import adafruit_requests as requests +import adafruit_connection_manager +import adafruit_requests from adafruit_fona.adafruit_fona import FONA from adafruit_fona.fona_3g import FONA3G import adafruit_fona.adafruit_fona_network as network -import adafruit_fona.adafruit_fona_socket as cellular_socket +import adafruit_fona.adafruit_fona_socket as pool # Get GPRS details and more from a secrets.py file try: @@ -45,8 +46,9 @@ time.sleep(0.5) print("Network Connected!") -# Initialize a requests object with a socket and cellular interface -requests.set_socket(cellular_socket, fona) +# create requests session +ssl_context = adafruit_connection_manager.create_fake_ssl_context(pool, fona) +requests = adafruit_requests.Session(pool, ssl_context) counter = 0 diff --git a/examples/fona_cheerlights.py b/examples/fona_cheerlights.py index a94ed0a..82a7167 100755 --- a/examples/fona_cheerlights.py +++ b/examples/fona_cheerlights.py @@ -7,12 +7,13 @@ import busio import digitalio import neopixel -import adafruit_requests as requests +import adafruit_connection_manager +import adafruit_requests import adafruit_fancyled.adafruit_fancyled as fancy from adafruit_fona.adafruit_fona import FONA from adafruit_fona.fona_3g import FONA3G import adafruit_fona.adafruit_fona_network as network -import adafruit_fona.adafruit_fona_socket as cellular_socket +import adafruit_fona.adafruit_fona_socket as pool # Get GPRS details and more from a secrets.py file try: @@ -47,8 +48,9 @@ time.sleep(0.5) print("Network Connected!") -# Initialize a requests object with a socket and cellular interface -requests.set_socket(cellular_socket, fona) +# create requests session +ssl_context = adafruit_connection_manager.create_fake_ssl_context(pool, fona) +requests = adafruit_requests.Session(pool, ssl_context) DATA_SOURCE = "http://api.thingspeak.com/channels/1417/feeds.json?results=1" DATA_LOCATION = ["feeds", 0, "field2"] diff --git a/examples/fona_simpletest.py b/examples/fona_simpletest.py index 07b7154..9b73bc6 100644 --- a/examples/fona_simpletest.py +++ b/examples/fona_simpletest.py @@ -6,11 +6,12 @@ import board import busio import digitalio -import adafruit_requests as requests +import adafruit_connection_manager +import adafruit_requests from adafruit_fona.adafruit_fona import FONA from adafruit_fona.fona_3g import FONA3G import adafruit_fona.adafruit_fona_network as network -import adafruit_fona.adafruit_fona_socket as cellular_socket +import adafruit_fona.adafruit_fona_socket as pool print("FONA Webclient Test") @@ -53,8 +54,9 @@ print("My IP address is:", fona.local_ip) print("IP lookup adafruit.com: %s" % fona.get_host_by_name("adafruit.com")) -# Initialize a requests object with a socket and cellular interface -requests.set_socket(cellular_socket, fona) +# create requests session +ssl_context = adafruit_connection_manager.create_fake_ssl_context(pool, fona) +requests = adafruit_requests.Session(pool, ssl_context) # fona._debug = True print("Fetching text from", TEXT_URL) From 33cfe6ab9b6d1692091caada9037fff69b2301d0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 7 Oct 2024 09:24:05 -0500 Subject: [PATCH 52/56] remove deprecated get_html_theme_path() call Signed-off-by: foamyguy --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 92e250b..02b2671 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -108,7 +108,6 @@ import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, From 00f9efafc592e964ea0f119b84ad8adbe1bfd33e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jan 2025 11:32:34 -0600 Subject: [PATCH 53/56] add sphinx configuration to rtd.yaml Signed-off-by: foamyguy --- .readthedocs.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 33c2a61..88bca9f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,9 @@ # Required version: 2 +sphinx: + configuration: docs/conf.py + build: os: ubuntu-20.04 tools: From 4d57929c195cff9b45d3808e0b699fa46a507f6f Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Wed, 26 Feb 2025 15:30:20 -0800 Subject: [PATCH 54/56] Remove secrets usage --- examples/fona_aio_post.py | 26 +++++++++++--------------- examples/fona_cheerlights.py | 15 ++++++--------- examples/fona_simpletest.py | 15 ++++++--------- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/examples/fona_aio_post.py b/examples/fona_aio_post.py index 97ca459..eae6b5c 100644 --- a/examples/fona_aio_post.py +++ b/examples/fona_aio_post.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT # pylint: disable=unused-import +from os import getenv import time import board import busio @@ -13,12 +14,13 @@ import adafruit_fona.adafruit_fona_network as network import adafruit_fona.adafruit_fona_socket as pool -# Get GPRS details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("GPRS secrets are kept in secrets.py, please add them there!") - raise +# Get FONA details and Adafruit IO keys, ensure these are setup in settings.toml +# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) +apn = getenv("apn") +apn_username = getenv("apn_username") +apn_password = getenv("apn_password") +aio_username = getenv("ADAFRUIT_AIO_USERNAME") +aio_key = getenv("ADAFRUIT_AIO_KEY") # Create a serial connection for the FONA uart = busio.UART(board.TX, board.RX) @@ -31,9 +33,7 @@ # fona = FONA3G(uart, rst) # Initialize cellular data network -network = network.CELLULAR( - fona, (secrets["apn"], secrets["apn_username"], secrets["apn_password"]) -) +network = network.CELLULAR(fona, (apn, apn_username, apn_password)) while not network.is_attached: print("Attaching to network...") @@ -58,13 +58,9 @@ feed = "test" payload = {"value": data} response = requests.post( - "http://io.adafruit.com/api/v2/" - + secrets["aio_username"] - + "/feeds/" - + feed - + "/data", + "http://io.adafruit.com/api/v2/" + aio_username + "/feeds/" + feed + "/data", json=payload, - headers={"X-AIO-KEY": secrets["aio_key"]}, + headers={"X-AIO-KEY": aio_key}, ) print(response.json()) response.close() diff --git a/examples/fona_cheerlights.py b/examples/fona_cheerlights.py index 82a7167..d0a1096 100755 --- a/examples/fona_cheerlights.py +++ b/examples/fona_cheerlights.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT # pylint: disable=unused-import +from os import getenv import time import board import busio @@ -15,12 +16,10 @@ import adafruit_fona.adafruit_fona_network as network import adafruit_fona.adafruit_fona_socket as pool -# Get GPRS details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("GPRS secrets are kept in secrets.py, please add them there!") - raise +# Get FONA details, ensure these are setup in settings.toml +apn = getenv("apn") +apn_username = getenv("apn_username") +apn_password = getenv("apn_password") # Create a serial connection for the FONA uart = busio.UART(board.TX, board.RX) @@ -33,9 +32,7 @@ # fona = FONA3G(uart, rst) # Initialize cellular data network -network = network.CELLULAR( - fona, (secrets["apn"], secrets["apn_username"], secrets["apn_password"]) -) +network = network.CELLULAR(fona, (apn, apn_username, apn_password)) while not network.is_attached: print("Attaching to network...") diff --git a/examples/fona_simpletest.py b/examples/fona_simpletest.py index 9b73bc6..f7db790 100644 --- a/examples/fona_simpletest.py +++ b/examples/fona_simpletest.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT # pylint: disable=unused-import +from os import getenv import time import board import busio @@ -18,12 +19,10 @@ TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html" JSON_URL = "http://api.coindesk.com/v1/bpi/currentprice/USD.json" -# Get GPRS details and more from a secrets.py file -try: - from secrets import secrets -except ImportError: - print("GPRS secrets are kept in secrets.py, please add them there!") - raise +# Get FONA details, ensure these are setup in settings.toml +apn = getenv("apn") +apn_username = getenv("apn_username") +apn_password = getenv("apn_password") # Create a serial connection for the FONA connection uart = busio.UART(board.TX, board.RX) @@ -36,9 +35,7 @@ # fona = FONA3G(uart, rst) # Initialize cellular data network -network = network.CELLULAR( - fona, (secrets["apn"], secrets["apn_username"], secrets["apn_password"]) -) +network = network.CELLULAR(fona, (apn, apn_username, apn_password)) while not network.is_attached: print("Attaching to network...") From 2aee4364adce035843b1d619de14579a7cb04fcc Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 14 May 2025 15:52:25 +0000 Subject: [PATCH 55/56] change to ruff --- .gitattributes | 11 + .pre-commit-config.yaml | 43 +-- .pylintrc | 399 ------------------------- README.rst | 6 +- adafruit_fona/adafruit_fona.py | 143 +++------ adafruit_fona/adafruit_fona_network.py | 22 +- adafruit_fona/adafruit_fona_socket.py | 23 +- adafruit_fona/fona_3g.py | 52 +--- docs/api.rst | 3 + docs/conf.py | 8 +- examples/fona_aio_post.py | 13 +- examples/fona_cheerlights.py | 15 +- examples/fona_simpletest.py | 13 +- examples/fona_sms.py | 5 +- examples/fona_sms_response.py | 5 +- ruff.toml | 108 +++++++ 16 files changed, 242 insertions(+), 627 deletions(-) create mode 100644 .gitattributes delete mode 100644 .pylintrc create mode 100644 ruff.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..21c125c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +.py text eol=lf +.rst text eol=lf +.txt text eol=lf +.yaml text eol=lf +.toml text eol=lf +.license text eol=lf +.md text eol=lf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 70ade69..ff19dde 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,42 +1,21 @@ -# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries # # SPDX-License-Identifier: Unlicense repos: - - repo: https://github.com/python/black - rev: 23.3.0 - hooks: - - id: black - - repo: https://github.com/fsfe/reuse-tool - rev: v1.1.2 - hooks: - - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/pycqa/pylint - rev: v2.17.4 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.4 hooks: - - id: pylint - name: pylint (library code) - types: [python] - args: - - --disable=consider-using-f-string - exclude: "^(docs/|examples/|tests/|setup.py$)" - - id: pylint - name: pylint (example code) - description: Run pylint rules on "examples/*.py" files - types: [python] - files: "^examples/" - args: - - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code - - id: pylint - name: pylint (test code) - description: Run pylint rules on "tests/*.py" files - types: [python] - files: "^tests/" - args: - - --disable=missing-docstring,consider-using-f-string,duplicate-code + - id: ruff-format + - id: ruff + args: ["--fix"] + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.1 + hooks: + - id: reuse diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index f945e92..0000000 --- a/.pylintrc +++ /dev/null @@ -1,399 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# -# SPDX-License-Identifier: Unlicense - -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Add files or directories to the ignore-list. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the ignore-list. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins=pylint.extensions.no_self_use - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call -disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -# notes=FIXME,XXX,TODO -notes=FIXME,XXX - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=board - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -# expected-line-ending-format= -expected-line-ending-format=LF - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=yes - -# Minimum lines number of a similarity. -min-similarity-lines=12 - - -[BASIC] - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class names -# class-rgx=[A-Z_][a-zA-Z0-9]+$ -class-rgx=[A-Z_][a-zA-Z0-9_]+$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -# good-names=i,j,k,ex,Run,_ -good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Maximum number of attributes for a class (see R0902). -# max-attributes=7 -max-attributes=11 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=1 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=builtins.Exception diff --git a/README.rst b/README.rst index 79d502f..8b7f415 100644 --- a/README.rst +++ b/README.rst @@ -13,9 +13,9 @@ Introduction :target: https://github.com/adafruit/Adafruit_CircuitPython_FONA/actions :alt: Build Status -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code Style: Black +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Code Style: Ruff CircuitPython library for the `Adafruit FONA `_ cellular module. diff --git a/adafruit_fona/adafruit_fona.py b/adafruit_fona/adafruit_fona.py index 1f244c7..c69c691 100644 --- a/adafruit_fona/adafruit_fona.py +++ b/adafruit_fona/adafruit_fona.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: MIT -# pylint: disable=too-many-lines - """ `adafruit_fona` ================================================================================ @@ -22,14 +20,17 @@ https://github.com/adafruit/circuitpython/releases """ + import time + from micropython import const from simpleio import map_range try: from typing import Optional, Tuple, Union - from circuitpython_typing import ReadableBuffer + from busio import UART + from circuitpython_typing import ReadableBuffer from digitalio import DigitalInOut try: @@ -67,7 +68,6 @@ FONA_SMS_STORAGE_INTERNAL = b'"ME"' # Internal storage on the FONA -# pylint: disable=too-many-instance-attributes, too-many-public-methods class FONA: """CircuitPython FONA module interface. @@ -80,12 +80,11 @@ class FONA: TCP_MODE = const(0) # TCP socket UDP_MODE = const(1) # UDP socket - # pylint: disable=too-many-arguments def __init__( self, uart: UART, rst: DigitalInOut, - ri: Optional[DigitalInOut] = None, # pylint: disable=invalid-name + ri: Optional[DigitalInOut] = None, debug: bool = False, ) -> None: self._buf = b"" # shared buffer @@ -100,7 +99,6 @@ def __init__( if not self._init_fona(): raise RuntimeError("Unable to find FONA. Please check connections.") - # pylint: disable=too-many-branches, too-many-statements def _init_fona(self) -> bool: """Initializes FONA module.""" self.reset() @@ -184,7 +182,6 @@ def reset(self) -> None: self._rst.value = True @property - # pylint: disable=too-many-return-statements def version(self) -> int: """The version of the FONA module. Can be FONA_800_L, FONA_800_H, FONA_808_V1, FONA_808_V2, FONA_3G_A, FONA3G_E. @@ -233,7 +230,6 @@ def gprs(self) -> bool: return False return True - # pylint: disable=too-many-return-statements def set_gprs( self, apn: Optional[Tuple[str, Optional[str], Optional[str]]] = None, @@ -257,9 +253,7 @@ def set_gprs( return False # disconnect all sockets - if not self._send_check_reply( - b"AT+CIPSHUT", reply=b"SHUT OK", timeout=20000 - ): + if not self._send_check_reply(b"AT+CIPSHUT", reply=b"SHUT OK", timeout=20000): return False if not self._send_check_reply(b"AT+CGATT=1", reply=REPLY_OK, timeout=10000): @@ -305,9 +299,7 @@ def set_gprs( return False # Open GPRS context - if not self._send_check_reply( - b"AT+SAPBR=1,1", reply=REPLY_OK, timeout=1850 - ): + if not self._send_check_reply(b"AT+SAPBR=1,1", reply=REPLY_OK, timeout=1850): return False # Bring up wireless connection @@ -316,12 +308,8 @@ def set_gprs( if not self.local_ip: return False - else: - # reset PDP state - if not self._send_check_reply( - b"AT+CIPSHUT", reply=b"SHUT OK", timeout=20000 - ): - return False + elif not self._send_check_reply(b"AT+CIPSHUT", reply=b"SHUT OK", timeout=20000): + return False return True @@ -381,14 +369,12 @@ def gps(self) -> int: status = 3 # assume 3D fix self._read_line() else: - raise NotImplementedError( - "FONA 808 v1 not currently supported by this library." - ) + raise NotImplementedError("FONA 808 v1 not currently supported by this library.") return status @gps.setter def gps(self, gps_on: bool = False) -> bool: - if self._fona_type not in (FONA_3G_A, FONA_3G_E, FONA_808_V1, FONA_808_V2): + if self._fona_type not in {FONA_3G_A, FONA_3G_E, FONA_808_V1, FONA_808_V2}: raise TypeError("GPS unsupported for this FONA module.") # check if already enabled or disabled @@ -406,27 +392,21 @@ def gps(self, gps_on: bool = False) -> bool: if self._fona_type == FONA_808_V2: # try GNS if not self._send_check_reply(b"AT+CGNSPWR=1", reply=REPLY_OK): return False - else: - if not self._send_parse_reply(b"AT+CGPSPWR=1", reply_data=REPLY_OK): - return False - else: - if self._fona_type == FONA_808_V2: # try GNS - if not self._send_check_reply(b"AT+CGNSPWR=0", reply=REPLY_OK): - return False - if not self._send_check_reply(b"AT+CGPSPWR=0", reply=REPLY_OK): - return False + elif not self._send_parse_reply(b"AT+CGPSPWR=1", reply_data=REPLY_OK): + return False + elif self._fona_type == FONA_808_V2: # try GNS + if not self._send_check_reply(b"AT+CGNSPWR=0", reply=REPLY_OK): + return False + if not self._send_check_reply(b"AT+CGPSPWR=0", reply=REPLY_OK): + return False return True - def pretty_ip( # pylint: disable=no-self-use, invalid-name - self, ip: ReadableBuffer - ) -> str: + def pretty_ip(self, ip: ReadableBuffer) -> str: """Converts a bytearray IP address to a dotted-quad string for printing""" return "%d.%d.%d.%d" % (ip[0], ip[1], ip[2], ip[3]) - def unpretty_ip( # pylint: disable=no-self-use, invalid-name - self, ip: str - ) -> bytes: + def unpretty_ip(self, ip: str) -> bytes: """Converts a dotted-quad string to a bytearray IP address""" octets = [int(x) for x in ip.split(".")] return bytes(octets) @@ -445,9 +425,8 @@ def enable_sms_notification(self, enable: bool = True) -> bool: if enable: if not self._send_check_reply(b"AT+CNMI=2,1\r\n", reply=REPLY_OK): return False - else: - if not self._send_check_reply(b"AT+CNMI=2,0\r\n", reply=REPLY_OK): - return False + elif not self._send_check_reply(b"AT+CNMI=2,0\r\n", reply=REPLY_OK): + return False return True def receive_sms(self) -> Tuple[str, str]: @@ -498,7 +477,7 @@ def send_sms(self, phone_number: int, message: str) -> bool: # write out message and ^z self._uart_write((message + chr(26)).encode()) - if self._fona_type in (FONA_3G_A, FONA_3G_E): + if self._fona_type in {FONA_3G_A, FONA_3G_E}: self._read_line(200) # eat first 'CRLF' self._read_line(200) # eat second 'CRLF' @@ -522,11 +501,8 @@ def num_sms(self, sim_storage: bool = True) -> int: if sim_storage: # ask how many SMS are stored if self._send_parse_reply(b"AT+CPMS?", FONA_SMS_STORAGE_SIM + b",", idx=1): return self._buf - else: - if self._send_parse_reply( - b"AT+CPMS?", FONA_SMS_STORAGE_INTERNAL + b",", idx=1 - ): - return self._buf + elif self._send_parse_reply(b"AT+CPMS?", FONA_SMS_STORAGE_INTERNAL + b",", idx=1): + return self._buf self._read_line() # eat OK if self._send_parse_reply(b"AT+CPMS?", b'"SM",', idx=1): @@ -545,9 +521,7 @@ def delete_sms(self, sms_slot: int) -> bool: if not self._send_check_reply(b"AT+CMGF=1", reply=REPLY_OK): return False - if not self._send_check_reply( - b"AT+CMGD=" + str(sms_slot).encode(), reply=REPLY_OK - ): + if not self._send_check_reply(b"AT+CMGD=" + str(sms_slot).encode(), reply=REPLY_OK): return False return True @@ -558,16 +532,13 @@ def delete_all_sms(self) -> bool: if not self._send_check_reply(b"AT+CMGF=1", reply=REPLY_OK): return False - if self._fona_type in (FONA_3G_A, FONA_3G_E): + if self._fona_type in {FONA_3G_A, FONA_3G_E}: num_sms = self.num_sms() for slot in range(0, num_sms): if not self.delete_sms(slot): return False - else: # DEL ALL on 808 - if not self._send_check_reply( - b'AT+CMGDA="DEL ALL"', reply=REPLY_OK, timeout=25000 - ): - return False + elif not self._send_check_reply(b'AT+CMGDA="DEL ALL"', reply=REPLY_OK, timeout=25000): + return False return True def read_sms(self, sms_slot: int) -> Tuple[str, str]: @@ -617,9 +588,7 @@ def get_host_by_name(self, hostname: str) -> Union[str, Literal[False]]: if isinstance(hostname, str): hostname = bytes(hostname, "utf-8") - if not self._send_check_reply( - b'AT+CDNSGIP="' + hostname + b'"\r\n', reply=REPLY_OK - ): + if not self._send_check_reply(b'AT+CDNSGIP="' + hostname + b'"\r\n', reply=REPLY_OK): return False self._read_line() @@ -655,9 +624,7 @@ def remote_ip(self, sock_num: int) -> str: :param int sock_num: Desired socket. """ - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." self._uart_write(b"AT+CIPSTATUS=" + str(sock_num).encode() + b"\r\n") self._read_line(100) @@ -670,9 +637,7 @@ def socket_status(self, sock_num: int) -> bool: :param int sock_num: Desired socket number. """ - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." if not self._send_check_reply(b"AT+CIPSTATUS", reply=REPLY_OK, timeout=100): return False @@ -700,9 +665,7 @@ def socket_available(self, sock_num: int) -> int: :param int sock_num: Desired socket to return bytes available from. """ - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." if not self._send_parse_reply( b"AT+CIPRXGET=4," + str(sock_num).encode(), @@ -711,7 +674,7 @@ def socket_available(self, sock_num: int) -> int: return False data = self._buf if self._debug: - print("\t {} bytes available.".format(self._buf)) + print(f"\t {self._buf} bytes available.") self._read_line() self._read_line() @@ -730,16 +693,10 @@ def socket_connect( :param int conn_mode: Connection mode (TCP/UDP) """ if self._debug: - print( - "*** Socket connect, protocol={}, port={}, ip={}".format( - conn_mode, port, dest - ) - ) + print(f"*** Socket connect, protocol={conn_mode}, port={port}, ip={dest}") self._uart.reset_input_buffer() - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." # Query local IP Address @@ -768,20 +725,17 @@ def socket_close(self, sock_num: int) -> bool: """ if self._debug: print("*** Closing socket #%d" % sock_num) - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." self._uart_write(b"AT+CIPCLOSE=" + str(sock_num).encode() + b"\r\n") self._read_line(3000) - if self._fona_type in (FONA_3G_A, FONA_3G_E): + if self._fona_type in {FONA_3G_A, FONA_3G_E}: if not self._expect_reply(REPLY_OK): return False - else: - if not self._expect_reply(b"CLOSE OK"): - return False + elif not self._expect_reply(b"CLOSE OK"): + return False return True def socket_read(self, sock_num: int, length: int) -> bytearray: @@ -792,9 +746,7 @@ def socket_read(self, sock_num: int, length: int) -> bytearray: :param int length: Desired length to read. """ self._read_line() - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." if self._debug: print("* socket read") @@ -816,9 +768,7 @@ def socket_write(self, sock_num: int, buffer: bytes, timeout: int = 3000) -> boo :param int timeout: Socket write timeout, in milliseconds. """ self._read_line() - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." self._uart.reset_input_buffer() @@ -971,9 +921,8 @@ def _send_check_reply( if send is None: if not self._get_reply(prefix=prefix, suffix=suffix, timeout=timeout): return False - else: - if not self._get_reply(send, timeout=timeout): - return False + elif not self._get_reply(send, timeout=timeout): + return False if not self._buf == reply: return False @@ -1002,9 +951,7 @@ def _send_check_reply_quoted( return False return True - def _get_reply_quoted( - self, prefix: bytes, suffix: bytes, timeout: int - ) -> Tuple[int, bytes]: + def _get_reply_quoted(self, prefix: bytes, suffix: bytes, timeout: int) -> Tuple[int, bytes]: """Send prefix, ", suffix, ", and newline. Returns: Response (and also fills buffer with response). diff --git a/adafruit_fona/adafruit_fona_network.py b/adafruit_fona/adafruit_fona_network.py index 5d71985..050e7c5 100755 --- a/adafruit_fona/adafruit_fona_network.py +++ b/adafruit_fona/adafruit_fona_network.py @@ -13,8 +13,9 @@ """ try: - from typing import Optional, Tuple, Type from types import TracebackType + from typing import Optional, Tuple, Type + from adafruit_fona.adafruit_fona import FONA except ImportError: pass @@ -35,9 +36,7 @@ class CELLULAR: and APN password. """ - def __init__( - self, fona: FONA, apn: Tuple[str, Optional[str], Optional[str]] - ) -> None: + def __init__(self, fona: FONA, apn: Tuple[str, Optional[str], Optional[str]]) -> None: self._iface = fona self._apn = apn self._network_connected = False @@ -47,10 +46,10 @@ def __init__( # These are numbers defined in adafruit_fona FONA versions # For some reason, we can't import them from the adafruit_fona file - if self._iface.version in (0x4, 0x5): + if self._iface.version in {0x4, 0x5}: self._network_type = NET_CDMA - if self._iface.version in (0x2, 0x3, 0x4, 0x5): + if self._iface.version in {0x2, 0x3, 0x4, 0x5}: self._iface.gps = True self._has_gps = True @@ -79,18 +78,13 @@ def iccid(self) -> str: def is_attached(self) -> bool: """Returns if the modem is attached to the network.""" if self._network_type == NET_GSM: - if ( - self._has_gps - and self._iface.gps == 3 - and self._iface.network_status == 1 - ): + if self._has_gps and self._iface.gps == 3 and self._iface.network_status == 1: return True if not self._has_gps and self._iface.network_status == 1: return True - else: # Attach CDMA network - if self._iface.ue_system_info == 1 and self._iface.network_status == 1: - return True + elif self._iface.ue_system_info == 1 and self._iface.network_status == 1: + return True return False @property diff --git a/adafruit_fona/adafruit_fona_socket.py b/adafruit_fona/adafruit_fona_socket.py index c20c518..2de6825 100644 --- a/adafruit_fona/adafruit_fona_socket.py +++ b/adafruit_fona/adafruit_fona_socket.py @@ -12,22 +12,25 @@ * Author(s): ladyada, Brent Rubell """ + import gc import time + from micropython import const try: - from typing import Optional, Tuple, Sequence + from typing import Optional, Sequence, Tuple + from adafruit_fona.adafruit_fona import FONA except ImportError: pass -_the_interface = None # pylint: disable=invalid-name +_the_interface = None def set_interface(iface: FONA) -> None: """Helper to set the global internet interface.""" - global _the_interface # pylint: disable=global-statement, invalid-name + global _the_interface _the_interface = iface @@ -56,7 +59,6 @@ def htons(x: int) -> int: SOCKETS = [] -# pylint: disable=too-many-arguments, unused-argument def getaddrinfo(host, port: int, family=0, socktype=0, proto=0, flags=0): """Translate the host/port argument into a sequence of 5-tuples that contain all the necessary arguments for creating a socket connected to that service. @@ -76,7 +78,6 @@ def gethostbyname(hostname: str) -> str: return addr.strip('"') -# pylint: disable=invalid-name, redefined-builtin class socket: """A simplified implementation of the Python 'socket' class for connecting to a FONA cellular module. @@ -130,23 +131,17 @@ def inet_aton(self, ip_string: str) -> bytearray: self._buffer = bytearray(self._buffer) return self._buffer - def connect( - self, address: Tuple[str, int], conn_mode: Optional[int] = None - ) -> None: + def connect(self, address: Tuple[str, int], conn_mode: Optional[int] = None) -> None: """Connect to a remote socket at address. (The format of address depends on the address family — see above.) :param tuple address: Remote socket as a (host, port) tuple. :param int conn_mode: Connection mode (TCP/UDP) """ - assert ( - conn_mode != 0x03 - ), "Error: SSL/TLS is not currently supported by CircuitPython." + assert conn_mode != 0x03, "Error: SSL/TLS is not currently supported by CircuitPython." host, port = address - if not _the_interface.socket_connect( - self.socknum, host, port, conn_mode=self._sock_type - ): + if not _the_interface.socket_connect(self.socknum, host, port, conn_mode=self._sock_type): raise RuntimeError("Failed to connect to host", host) self._buffer = b"" diff --git a/adafruit_fona/fona_3g.py b/adafruit_fona/fona_3g.py index cd8c609..4515660 100755 --- a/adafruit_fona/fona_3g.py +++ b/adafruit_fona/fona_3g.py @@ -20,11 +20,14 @@ https://github.com/adafruit/circuitpython/releases """ + from micropython import const + from .adafruit_fona import FONA, REPLY_OK try: from typing import Optional, Tuple, Union + from busio import UART from digitalio import DigitalInOut @@ -62,9 +65,7 @@ def __init__( def set_baudrate(self, baudrate: int) -> bool: """Sets the FONA's UART baudrate.""" - if not self._send_check_reply( - b"AT+IPREX=" + str(baudrate).encode(), reply=REPLY_OK - ): + if not self._send_check_reply(b"AT+IPREX=" + str(baudrate).encode(), reply=REPLY_OK): return False return True @@ -108,7 +109,6 @@ def local_ip(self) -> Optional[str]: return None return self._buf - # pylint: disable=too-many-return-statements def set_gprs( self, apn: Optional[Tuple[str, Optional[str], Optional[str]]] = None, @@ -153,12 +153,8 @@ def set_gprs( if not self.local_ip: return True - else: - # reset PDP state - if not self._send_check_reply( - b"AT+NETCLOSE", reply=b"Network closed", timeout=20000 - ): - return False + elif not self._send_check_reply(b"AT+NETCLOSE", reply=b"Network closed", timeout=20000): + return False return True ### Socket API (TCP, UDP) ### @@ -174,9 +170,7 @@ def tx_timeout(self) -> bool: @tx_timeout.setter def tx_timeout(self, timeout: int) -> bool: self._read_line() - if not self._send_check_reply( - b"AT+CIPTIMEOUT=" + str(timeout).encode(), reply=REPLY_OK - ): + if not self._send_check_reply(b"AT+CIPTIMEOUT=" + str(timeout).encode(), reply=REPLY_OK): return False return True @@ -221,9 +215,7 @@ def get_socket(self) -> int: print("Allocated socket #%d" % socket) return socket - def socket_connect( - self, sock_num: int, dest: str, port: int, conn_mode: int = 0 - ) -> bool: + def socket_connect(self, sock_num: int, dest: str, port: int, conn_mode: int = 0) -> bool: """Connects to a destination IP address or hostname. By default, we use conn_mode TCP_MODE but we may also use UDP_MODE. @@ -233,21 +225,13 @@ def socket_connect( :param int conn_mode: Connection mode (TCP/UDP) """ if self._debug: - print( - "*** Socket connect, protocol={}, port={}, ip={}".format( - conn_mode, port, dest - ) - ) + print(f"*** Socket connect, protocol={conn_mode}, port={port}, ip={dest}") self._uart.reset_input_buffer() - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." self._send_check_reply(b"AT+CIPHEAD=0", reply=REPLY_OK) # do not show ip header - self._send_check_reply( - b"AT+CIPSRIP=0", reply=REPLY_OK - ) # do not show remote ip/port + self._send_check_reply(b"AT+CIPSRIP=0", reply=REPLY_OK) # do not show remote ip/port self._send_check_reply(b"AT+CIPRXGET=1", reply=REPLY_OK) # manually get data self._uart_write(b"AT+CIPOPEN=" + str(sock_num).encode()) @@ -267,9 +251,7 @@ def remote_ip(self, sock_num: int) -> str: :param int sock_num: Desired socket number """ self._read_line() - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." self._uart_write(b"AT+CIPOPEN?\r\n") @@ -290,19 +272,13 @@ def socket_write(self, sock_num: int, buffer: bytes, timeout: int = 120000) -> b :param int timeout: Socket write timeout, in milliseconds. Defaults to 120000ms. """ self._read_line() - assert ( - sock_num < FONA_MAX_SOCKETS - ), "Provided socket exceeds the maximum number of \ + assert sock_num < FONA_MAX_SOCKETS, "Provided socket exceeds the maximum number of \ sockets for the FONA module." self._uart.reset_input_buffer() self._uart_write( - b"AT+CIPSEND=" - + str(sock_num).encode() - + b"," - + str(len(buffer)).encode() - + b"\r\n" + b"AT+CIPSEND=" + str(sock_num).encode() + b"," + str(len(buffer)).encode() + b"\r\n" ) self._read_line() if self._buf[0] != 62: diff --git a/docs/api.rst b/docs/api.rst index 7846032..1e1d2e5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,6 +4,9 @@ .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. use this format as the module name: "adafruit_foo.foo" +API Reference +############# + .. automodule:: adafruit_fona.adafruit_fona :members: diff --git a/docs/conf.py b/docs/conf.py index 02b2671..b700101 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- - # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # # SPDX-License-Identifier: MIT +import datetime import os import sys -import datetime sys.path.insert(0, os.path.abspath("..")) @@ -52,9 +50,7 @@ creation_year = "2020" current_year = str(datetime.datetime.now().year) year_duration = ( - current_year - if current_year == creation_year - else creation_year + " - " + current_year + current_year if current_year == creation_year else creation_year + " - " + current_year ) copyright = year_duration + " Brent Rubell, ladyada" author = "Brent Rubell, ladyada" diff --git a/examples/fona_aio_post.py b/examples/fona_aio_post.py index eae6b5c..28e79c3 100644 --- a/examples/fona_aio_post.py +++ b/examples/fona_aio_post.py @@ -1,18 +1,19 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT -# pylint: disable=unused-import -from os import getenv import time +from os import getenv + +import adafruit_connection_manager +import adafruit_requests import board import busio import digitalio -import adafruit_connection_manager -import adafruit_requests -from adafruit_fona.adafruit_fona import FONA -from adafruit_fona.fona_3g import FONA3G + import adafruit_fona.adafruit_fona_network as network import adafruit_fona.adafruit_fona_socket as pool +from adafruit_fona.adafruit_fona import FONA +from adafruit_fona.fona_3g import FONA3G # Get FONA details and Adafruit IO keys, ensure these are setup in settings.toml # (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) diff --git a/examples/fona_cheerlights.py b/examples/fona_cheerlights.py index d0a1096..68fc4d9 100755 --- a/examples/fona_cheerlights.py +++ b/examples/fona_cheerlights.py @@ -1,20 +1,21 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT -# pylint: disable=unused-import -from os import getenv import time +from os import getenv + +import adafruit_connection_manager +import adafruit_fancyled.adafruit_fancyled as fancy +import adafruit_requests import board import busio import digitalio import neopixel -import adafruit_connection_manager -import adafruit_requests -import adafruit_fancyled.adafruit_fancyled as fancy -from adafruit_fona.adafruit_fona import FONA -from adafruit_fona.fona_3g import FONA3G + import adafruit_fona.adafruit_fona_network as network import adafruit_fona.adafruit_fona_socket as pool +from adafruit_fona.adafruit_fona import FONA +from adafruit_fona.fona_3g import FONA3G # Get FONA details, ensure these are setup in settings.toml apn = getenv("apn") diff --git a/examples/fona_simpletest.py b/examples/fona_simpletest.py index f7db790..11af0a5 100644 --- a/examples/fona_simpletest.py +++ b/examples/fona_simpletest.py @@ -1,18 +1,19 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT -# pylint: disable=unused-import -from os import getenv import time +from os import getenv + +import adafruit_connection_manager +import adafruit_requests import board import busio import digitalio -import adafruit_connection_manager -import adafruit_requests -from adafruit_fona.adafruit_fona import FONA -from adafruit_fona.fona_3g import FONA3G + import adafruit_fona.adafruit_fona_network as network import adafruit_fona.adafruit_fona_socket as pool +from adafruit_fona.adafruit_fona import FONA +from adafruit_fona.fona_3g import FONA3G print("FONA Webclient Test") diff --git a/examples/fona_sms.py b/examples/fona_sms.py index a516265..18a9436 100755 --- a/examples/fona_sms.py +++ b/examples/fona_sms.py @@ -1,11 +1,12 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT -# pylint: disable=unused-import import time + import board import busio import digitalio + from adafruit_fona.adafruit_fona import FONA, FONA_3G_A, FONA_3G_E from adafruit_fona.fona_3g import FONA3G @@ -39,7 +40,7 @@ print("%d SMS's on SIM Card" % num_sms) # FONA3G SMS memory slots start at 0 -if fona.version in (FONA_3G_A, FONA_3G_E): +if fona.version in {FONA_3G_A, FONA_3G_E}: sms_idx = 0 else: # FONA800 and FONA808 SMS slots start at 1 sms_idx = 1 diff --git a/examples/fona_sms_response.py b/examples/fona_sms_response.py index 5595d19..b073832 100755 --- a/examples/fona_sms_response.py +++ b/examples/fona_sms_response.py @@ -1,11 +1,12 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT -# pylint: disable=unused-import import time + import board import busio import digitalio + from adafruit_fona.adafruit_fona import FONA from adafruit_fona.fona_3g import FONA3G @@ -38,7 +39,7 @@ sender, message = fona.receive_sms() if message: - print("Incoming SMS from {}: {}".format(sender, message)) + print(f"Incoming SMS from {sender}: {message}") # Reply back! print("Sending response...") diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..b45e467 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,108 @@ +# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +target-version = "py38" +line-length = 100 + +[lint] +preview = true +select = ["I", "PL", "UP"] + +extend-select = [ + "D419", # empty-docstring + "E501", # line-too-long + "W291", # trailing-whitespace + "PLC0414", # useless-import-alias + "PLC2401", # non-ascii-name + "PLC2801", # unnecessary-dunder-call + "PLC3002", # unnecessary-direct-lambda-call + "E999", # syntax-error + "PLE0101", # return-in-init + "F706", # return-outside-function + "F704", # yield-outside-function + "PLE0116", # continue-in-finally + "PLE0117", # nonlocal-without-binding + "PLE0241", # duplicate-bases + "PLE0302", # unexpected-special-method-signature + "PLE0604", # invalid-all-object + "PLE0605", # invalid-all-format + "PLE0643", # potential-index-error + "PLE0704", # misplaced-bare-raise + "PLE1141", # dict-iter-missing-items + "PLE1142", # await-outside-async + "PLE1205", # logging-too-many-args + "PLE1206", # logging-too-few-args + "PLE1307", # bad-string-format-type + "PLE1310", # bad-str-strip-call + "PLE1507", # invalid-envvar-value + "PLE2502", # bidirectional-unicode + "PLE2510", # invalid-character-backspace + "PLE2512", # invalid-character-sub + "PLE2513", # invalid-character-esc + "PLE2514", # invalid-character-nul + "PLE2515", # invalid-character-zero-width-space + "PLR0124", # comparison-with-itself + "PLR0202", # no-classmethod-decorator + "PLR0203", # no-staticmethod-decorator + "UP004", # useless-object-inheritance + "PLR0206", # property-with-parameters + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLR0914", # too-many-locals + "PLR0915", # too-many-statements + "PLR0916", # too-many-boolean-expressions + "PLR1702", # too-many-nested-blocks + "PLR1704", # redefined-argument-from-local + "PLR1711", # useless-return + "C416", # unnecessary-comprehension + "PLR1733", # unnecessary-dict-index-lookup + "PLR1736", # unnecessary-list-index-lookup + + # ruff reports this rule is unstable + #"PLR6301", # no-self-use + + "PLW0108", # unnecessary-lambda + "PLW0120", # useless-else-on-loop + "PLW0127", # self-assigning-variable + "PLW0129", # assert-on-string-literal + "B033", # duplicate-value + "PLW0131", # named-expr-without-context + "PLW0245", # super-without-brackets + "PLW0406", # import-self + "PLW0602", # global-variable-not-assigned + "PLW0603", # global-statement + "PLW0604", # global-at-module-level + + # fails on the try: import typing used by libraries + #"F401", # unused-import + + "F841", # unused-variable + "E722", # bare-except + "PLW0711", # binary-op-exception + "PLW1501", # bad-open-mode + "PLW1508", # invalid-envvar-default + "PLW1509", # subprocess-popen-preexec-fn + "PLW2101", # useless-with-lock + "PLW3301", # nested-min-max +] + +ignore = [ + "PLR2004", # magic-value-comparison + "UP030", # format literals + "PLW1514", # unspecified-encoding + "PLR0913", # too-many-arguments + "PLR0915", # too-many-statements + "PLR0917", # too-many-positional-arguments + "PLR0904", # too-many-public-methods + "PLR0912", # too-many-branches + "PLR0916", # too-many-boolean-expressions + "PLR6301", # method-could-be-function + "PLR0911", # too-many-return-statements + "PLW0603", # global-statement +] + +[format] +line-ending = "lf" From b9049f03403c5be20b40836b5aad039276b293a6 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 4 Jun 2025 10:00:20 -0500 Subject: [PATCH 56/56] update rtd.yml file Signed-off-by: foamyguy --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 88bca9f..255dafd 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -12,7 +12,7 @@ sphinx: configuration: docs/conf.py build: - os: ubuntu-20.04 + os: ubuntu-lts-latest tools: python: "3" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy