Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package micropython-lib for openSUSE:Factory
checked in at 2026-04-28 11:58:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/micropython-lib (Old)
and /work/SRC/openSUSE:Factory/.micropython-lib.new.11940 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "micropython-lib"
Tue Apr 28 11:58:10 2026 rev:7 rq:1349591 version:1.28.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/micropython-lib/micropython-lib.changes
2026-02-20 17:43:09.168709777 +0100
+++
/work/SRC/openSUSE:Factory/.micropython-lib.new.11940/micropython-lib.changes
2026-04-28 12:02:06.215797998 +0200
@@ -1,0 +2,16 @@
+Mon Apr 27 10:10:03 UTC 2026 - Simon Haendler <[email protected]>
+
+- Update to 1.28.0
+ * string: Convert string module to package and import templatelib.
+ * unix-ffi/_libc: Extend FreeBSD libc versions range.
+ * senml/docs: Correct capitalization of 'MicroPython'.
+ * unix-ffi/machine: Retrieve a unique identifier if one is known.
+ * unix-ffi/re: Add tests for empty string match in ffi regex.
+ * unix-ffi/re: Handle PCRE2_UNSET in group and groups methods.
+ * lsm6dsox: Add pedometer example code.
+ * lsm6dsox: Add pedometer support.
+ * sdcard: Add read/write speed test to sdtest.
+ * sdcard: Compute CRC7 for all SPI commands.
+ * sdcard: Send stop bit after multi-block read/write.
+
+-------------------------------------------------------------------
Old:
----
micropython-lib-1.27.0.tar.gz
New:
----
micropython-lib-1.28.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ micropython-lib.spec ++++++
--- /var/tmp/diff_new_pack.dCOQ19/_old 2026-04-28 12:02:06.759820535 +0200
+++ /var/tmp/diff_new_pack.dCOQ19/_new 2026-04-28 12:02:06.759820535 +0200
@@ -17,7 +17,7 @@
Name: micropython-lib
-Version: 1.27.0
+Version: 1.28.0
Release: 0
Summary: Core Python libraries ported to MicroPython
License: MIT AND Python-2.0
++++++ micropython-lib-1.27.0.tar.gz -> micropython-lib-1.28.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/drivers/imu/lsm6dsox/lsm6dsox.py
new/micropython-lib-1.28.0/micropython/drivers/imu/lsm6dsox/lsm6dsox.py
--- old/micropython-lib-1.27.0/micropython/drivers/imu/lsm6dsox/lsm6dsox.py
2025-12-08 01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/micropython/drivers/imu/lsm6dsox/lsm6dsox.py
2026-03-23 01:17:33.000000000 +0100
@@ -60,6 +60,13 @@
_OUTX_L_G = const(0x22)
_OUTX_L_XL = const(0x28)
_MLC_STATUS = const(0x38)
+_MD1_CFG = const(0x5E)
+_MD2_CFG = const(0x5F)
+
+_PAGE_SEL = const(0x02)
+_PAGE_ADDRESS = const(0x08)
+_PAGE_VALUE = const(0x09)
+_PAGE_RW = const(0x17)
_DEFAULT_ADDR = const(0x6A)
_WHO_AM_I_REG = const(0x0F)
@@ -75,6 +82,17 @@
_EMB_FUNC_EN_A = const(0x04)
_EMB_FUNC_EN_B = const(0x05)
+_EMB_FUNC_INT1 = const(0x0A)
+_EMB_FUNC_INT2 = const(0x0E)
+_EMB_FUNC_SRC = const(0x64)
+_STEP_COUNTER_L = const(0x62)
+
+_PEDO_DEB_STEPS_CONF = const(0x0184)
+
+_PEDO_EN_MASK = const(0x08)
+_PEDO_RST_STEP_MASK = const(0x80)
+_PEDO_INT_MASK = const(0x08)
+_INT_EMB_FUNC_MASK = const(0x02)
class LSM6DSOX:
@@ -108,8 +126,9 @@
if self._read_reg(_WHO_AM_I_REG) != 108:
raise OSError("No LSM6DS device was found at address 0x%x" %
(self.address))
- # allocate scratch buffer for efficient conversions and memread op's
+ # allocate scratch buffers for efficient conversions and memread op's
self.scratch_int = array.array("h", [0, 0, 0])
+ self.scratch_2b = bytearray(2)
SCALE_GYRO = {250: 0, 500: 1, 1000: 2, 2000: 3}
SCALE_ACCEL = {2: 0, 4: 2, 8: 3, 16: 1}
@@ -185,6 +204,9 @@
finally:
self.cs(1)
+ def _modify_bits(self, reg, clr_mask=0, set_mask=0):
+ self._write_reg(reg, (self._read_reg(reg) & ~clr_mask) | set_mask)
+
def _read_reg_into(self, reg, buf):
if self._use_i2c:
self.bus.readfrom_mem_into(self.address, reg, buf)
@@ -196,8 +218,43 @@
finally:
self.cs(1)
+ def _select_page(self, address, value=None):
+ """
+ Selects the embedded function page and reads/writes the value at the
given address.
+ If value is None, it reads the value at the address. Otherwise, it
writes the value to the address.
+ """
+ msb = (address >> 8) & 0x0F # MSB is the page number
+ lsb = address & 0xFF # LSB is the register address within the page
+
+ self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+
+ rw_bit = 0x20 if value is None else 0x40
+ # Clear both read and write bits first, then set read (bit 5) or write
(bit 6).
+ self._modify_bits(_PAGE_RW, clr_mask=0x60, set_mask=rw_bit)
+
+ # select page
+ self._write_reg(_PAGE_SEL, (msb << 4) | 0x01)
+
+ # set page addr
+ self._write_reg(_PAGE_ADDRESS, lsb)
+
+ val = None
+ if value is None:
+ # read value
+ val = self._read_reg(_PAGE_VALUE)
+ else:
+ # write value
+ self._write_reg(_PAGE_VALUE, value)
+
+ # unset page write/read and page_sel
+ self._write_reg(_PAGE_SEL, 0x01)
+ self._modify_bits(_PAGE_RW, clr_mask=rw_bit)
+
+ self.set_mem_bank(_FUNC_CFG_BANK_USER)
+ return val
+
def reset(self):
- self._write_reg(_CTRL3_C, self._read_reg(_CTRL3_C) | 0x1)
+ self._modify_bits(_CTRL3_C, set_mask=0x1)
for i in range(10):
if (self._read_reg(_CTRL3_C) & 0x01) == 0:
return
@@ -205,8 +262,7 @@
raise OSError("Failed to reset LSM6DS device.")
def set_mem_bank(self, bank):
- cfg = self._read_reg(_FUNC_CFG_ACCESS) & 0x3F
- self._write_reg(_FUNC_CFG_ACCESS, cfg | (bank << 6))
+ self._modify_bits(_FUNC_CFG_ACCESS, clr_mask=0xC0, set_mask=(bank <<
6))
def set_embedded_functions(self, enable, emb_ab=None):
self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
@@ -234,18 +290,18 @@
emb_ab = self.set_embedded_functions(False)
# Disable I3C interface
- self._write_reg(_CTRL9_XL, self._read_reg(_CTRL9_XL) | 0x01)
+ self._modify_bits(_CTRL9_XL, set_mask=0x01)
# Enable Block Data Update
- self._write_reg(_CTRL3_C, self._read_reg(_CTRL3_C) | 0x40)
+ self._modify_bits(_CTRL3_C, set_mask=0x40)
# Route signals on interrupt pin 1
self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
- self._write_reg(_MLC_INT1, self._read_reg(_MLC_INT1) & 0x01)
+ self._modify_bits(_MLC_INT1, clr_mask=0xFE)
self.set_mem_bank(_FUNC_CFG_BANK_USER)
# Configure interrupt pin mode
- self._write_reg(_TAP_CFG0, self._read_reg(_TAP_CFG0) | 0x41)
+ self._modify_bits(_TAP_CFG0, set_mask=0x41)
self.set_embedded_functions(True, emb_ab)
@@ -258,6 +314,36 @@
self.set_mem_bank(_FUNC_CFG_BANK_USER)
return buf
+ def pedometer_config(self, enable=True, debounce=10, int1_enable=False,
int2_enable=False):
+ """Configure the pedometer features."""
+ self._select_page(_PEDO_DEB_STEPS_CONF, debounce)
+
+ if int1_enable:
+ self._modify_bits(_MD1_CFG, set_mask=_INT_EMB_FUNC_MASK)
+ if int2_enable:
+ self._modify_bits(_MD2_CFG, set_mask=_INT_EMB_FUNC_MASK)
+
+ self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+
+ self._modify_bits(_EMB_FUNC_EN_A, _PEDO_EN_MASK, enable and
_PEDO_EN_MASK)
+ self._modify_bits(_EMB_FUNC_INT1, _PEDO_INT_MASK, int1_enable and
_PEDO_INT_MASK)
+ self._modify_bits(_EMB_FUNC_INT2, _PEDO_INT_MASK, int2_enable and
_PEDO_INT_MASK)
+
+ self.set_mem_bank(_FUNC_CFG_BANK_USER)
+
+ def pedometer_reset(self):
+ """Reset the step counter."""
+ self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+ self._modify_bits(_EMB_FUNC_SRC, set_mask=_PEDO_RST_STEP_MASK)
+ self.set_mem_bank(_FUNC_CFG_BANK_USER)
+
+ def steps(self):
+ """Return the number of detected steps."""
+ self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
+ self._read_reg_into(_STEP_COUNTER_L, self.scratch_2b)
+ self.set_mem_bank(_FUNC_CFG_BANK_USER)
+ return self.scratch_2b[0] | (self.scratch_2b[1] << 8)
+
def gyro(self):
"""Returns gyroscope vector in degrees/sec."""
mv = memoryview(self.scratch_int)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/drivers/imu/lsm6dsox/lsm6dsox_pedometer.py
new/micropython-lib-1.28.0/micropython/drivers/imu/lsm6dsox/lsm6dsox_pedometer.py
---
old/micropython-lib-1.27.0/micropython/drivers/imu/lsm6dsox/lsm6dsox_pedometer.py
1970-01-01 01:00:00.000000000 +0100
+++
new/micropython-lib-1.28.0/micropython/drivers/imu/lsm6dsox/lsm6dsox_pedometer.py
2026-03-23 01:17:33.000000000 +0100
@@ -0,0 +1,55 @@
+"""
+LSM6DSOX IMU Pedometer Example.
+
+This example demonstrates how to use the built-in pedometer feature of the
LSM6DSOX IMU.
+The pedometer counts the number of steps taken based on the accelerometer data
+and can generate interrupts when a step is detected.
+
+Copyright (C) Arduino s.r.l. and/or its affiliated companies
+"""
+
+import time
+from lsm6dsox import LSM6DSOX
+
+from machine import Pin, I2C
+
+lsm = LSM6DSOX(I2C(0))
+# Or init in SPI mode.
+# lsm = LSM6DSOX(SPI(5), cs=Pin(10))
+
+# Enable the pedometer feature, set debounce steps to 5, and enable interrupts
on both INT1 and INT2.
+# Default debounce steps is 10. This means that after a step is detected, the
pedometer
+# will ignore any new steps for the next 5 step detections. This can help to
filter out
+# false positives and improve step counting accuracy.
+# If you just want to enable the pedometer, simply call
lsm.pedometer_config(enable=True).
+lsm.pedometer_config(debounce=5, int1_enable=True, int2_enable=True)
+
+# Register interrupt handler on a Pin. e.g. D8
+# The interrupt pins are push-pull outputs by default that go low when a step
is detected.
+# You can connect either INT1 or INT2 to the interrupt pin.
+interrupt_pin = Pin("D8", Pin.IN) # Change this to your desired interrupt pin.
+interrupt_fired = False # Flag to indicate if the interrupt has been fired.
+
+
+def on_step_detected(pin):
+ global interrupt_fired
+ interrupt_fired = True
+
+
+# Configure the interrupt pin to trigger on falling edge (active low) when a
step is detected.
+interrupt_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_step_detected)
+
+last_steps = None # Keep track of the last step count to detect changes.
+
+while True:
+ if interrupt_fired:
+ print("Step detected!")
+ interrupt_fired = False # Reset the flag after handling the interrupt.
+
+ steps = lsm.steps()
+
+ if steps != last_steps:
+ print(f"Steps: {steps}")
+ last_steps = steps
+
+ time.sleep_ms(100)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/drivers/imu/lsm6dsox/manifest.py
new/micropython-lib-1.28.0/micropython/drivers/imu/lsm6dsox/manifest.py
--- old/micropython-lib-1.27.0/micropython/drivers/imu/lsm6dsox/manifest.py
2025-12-08 01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/micropython/drivers/imu/lsm6dsox/manifest.py
2026-03-23 01:17:33.000000000 +0100
@@ -1,2 +1,2 @@
-metadata(description="ST LSM6DSOX imu driver.", version="1.0.1")
+metadata(description="ST LSM6DSOX imu driver.", version="1.1.0")
module("lsm6dsox.py", opt=3)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/drivers/storage/sdcard/manifest.py
new/micropython-lib-1.28.0/micropython/drivers/storage/sdcard/manifest.py
--- old/micropython-lib-1.27.0/micropython/drivers/storage/sdcard/manifest.py
2025-12-08 01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/micropython/drivers/storage/sdcard/manifest.py
2026-03-23 01:17:33.000000000 +0100
@@ -1,3 +1,3 @@
-metadata(description="SDCard block device driver.", version="0.1.1")
+metadata(description="SDCard block device driver.", version="0.2.0")
module("sdcard.py", opt=3)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/drivers/storage/sdcard/sdcard.py
new/micropython-lib-1.28.0/micropython/drivers/storage/sdcard/sdcard.py
--- old/micropython-lib-1.27.0/micropython/drivers/storage/sdcard/sdcard.py
2025-12-08 01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/micropython/drivers/storage/sdcard/sdcard.py
2026-03-23 01:17:33.000000000 +0100
@@ -38,6 +38,15 @@
_TOKEN_DATA = const(0xFE)
+def _crc7(buf, n):
+ crc = 0
+ for i in range(n):
+ crc ^= buf[i]
+ for j in range(8):
+ crc = ((crc << 1) ^ (0x12 * (crc >> 7))) & 0xFF
+ return crc
+
+
class SDCard:
def __init__(self, spi, cs, baudrate=1320000):
self.spi = spi
@@ -76,13 +85,13 @@
# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
for _ in range(5):
- if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
+ if self.cmd(0, 0) == _R1_IDLE_STATE:
break
else:
raise OSError("no SD card")
# CMD8: determine card version
- r = self.cmd(8, 0x01AA, 0x87, 4)
+ r = self.cmd(8, 0x01AA, 4)
if r == _R1_IDLE_STATE:
self.init_card_v2()
elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
@@ -92,7 +101,7 @@
# get the number of sectors
# CMD9: response R2 (R1 byte + 16-byte block read)
- if self.cmd(9, 0, 0, 0, False) != 0:
+ if self.cmd(9, 0, 0, False) != 0:
raise OSError("no response from SD card")
csd = bytearray(16)
self.readinto(csd)
@@ -109,7 +118,7 @@
# print('sectors', self.sectors)
# CMD16: set block length to 512 bytes
- if self.cmd(16, 512, 0) != 0:
+ if self.cmd(16, 512) != 0:
raise OSError("can't set 512 block size")
# set to high data rate now that it's initialised
@@ -118,8 +127,8 @@
def init_card_v1(self):
for i in range(_CMD_TIMEOUT):
time.sleep_ms(50)
- self.cmd(55, 0, 0)
- if self.cmd(41, 0, 0) == 0:
+ self.cmd(55, 0)
+ if self.cmd(41, 0) == 0:
# SDSC card, uses byte addressing in read/write/erase commands
self.cdv = 512
# print("[SDCard] v1 card")
@@ -129,10 +138,10 @@
def init_card_v2(self):
for i in range(_CMD_TIMEOUT):
time.sleep_ms(50)
- self.cmd(58, 0, 0, 4)
- self.cmd(55, 0, 0)
- if self.cmd(41, 0x40000000, 0) == 0:
- self.cmd(58, 0, 0, -4) # 4-byte response, negative means keep
the first byte
+ self.cmd(58, 0, 4)
+ self.cmd(55, 0)
+ if self.cmd(41, 0x40000000) == 0:
+ self.cmd(58, 0, -4) # 4-byte response, negative means keep
the first byte
ocr = self.tokenbuf[0] # get first byte of response, which is
OCR
if not ocr & 0x40:
# SDSC card, uses byte addressing in read/write/erase
commands
@@ -144,7 +153,7 @@
return
raise OSError("timeout waiting for v2 card")
- def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
+ def cmd(self, cmd, arg, final=0, release=True, skip1=False):
self.cs(0)
# create and send the command
@@ -154,7 +163,7 @@
buf[2] = arg >> 16
buf[3] = arg >> 8
buf[4] = arg
- buf[5] = crc
+ buf[5] = _crc7(buf, 5) | 0x01 # ensure stop bit is always set
self.spi.write(buf)
if skip1:
@@ -250,7 +259,7 @@
assert nblocks and not len(buf) % 512, "Buffer length is invalid"
if nblocks == 1:
# CMD17: set read address for single block
- if self.cmd(17, block_num * self.cdv, 0, release=False) != 0:
+ if self.cmd(17, block_num * self.cdv, release=False) != 0:
# release the card
self.cs(1)
raise OSError(5) # EIO
@@ -258,7 +267,7 @@
self.readinto(buf)
else:
# CMD18: set read address for multiple blocks
- if self.cmd(18, block_num * self.cdv, 0, release=False) != 0:
+ if self.cmd(18, block_num * self.cdv, release=False) != 0:
# release the card
self.cs(1)
raise OSError(5) # EIO
@@ -269,7 +278,7 @@
self.readinto(mv[offset : offset + 512])
offset += 512
nblocks -= 1
- if self.cmd(12, 0, 0xFF, skip1=True):
+ if self.cmd(12, 0, skip1=True):
raise OSError(5) # EIO
def writeblocks(self, block_num, buf):
@@ -281,14 +290,14 @@
assert nblocks and not err, "Buffer length is invalid"
if nblocks == 1:
# CMD24: set write address for single block
- if self.cmd(24, block_num * self.cdv, 0) != 0:
+ if self.cmd(24, block_num * self.cdv) != 0:
raise OSError(5) # EIO
# send the data
self.write(_TOKEN_DATA, buf)
else:
# CMD25: set write address for first block
- if self.cmd(25, block_num * self.cdv, 0) != 0:
+ if self.cmd(25, block_num * self.cdv) != 0:
raise OSError(5) # EIO
# send the data
offset = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/drivers/storage/sdcard/sdtest.py
new/micropython-lib-1.28.0/micropython/drivers/storage/sdcard/sdtest.py
--- old/micropython-lib-1.27.0/micropython/drivers/storage/sdcard/sdtest.py
2025-12-08 01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/micropython/drivers/storage/sdcard/sdtest.py
2026-03-23 01:17:33.000000000 +0100
@@ -2,6 +2,7 @@
# Peter hinch 30th Jan 2016
import machine
import os
+import time
import sdcard
@@ -44,6 +45,26 @@
result2 = f.read()
print(len(result2), "bytes read")
+ fn = "/fc/speed.bin"
+ buf = bytearray(32768) # 32 KB buffer
+
+ print()
+ print("Write speed test")
+ t = time.ticks_ms()
+ with open(fn, "wb") as f:
+ for _ in range(32): # 1 MB total
+ f.write(buf)
+ elapsed = time.ticks_diff(time.ticks_ms(), t)
+ print("{} KB/s".format(32768 * 32 // elapsed))
+
+ print("Read speed test")
+ t = time.ticks_ms()
+ with open(fn, "rb") as f:
+ while f.readinto(buf):
+ pass
+ elapsed = time.ticks_diff(time.ticks_ms(), t)
+ print("{} KB/s".format(32768 * 32 // elapsed))
+
os.umount("/fc")
print()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/micropython/senml/docs/index.md
new/micropython-lib-1.28.0/micropython/senml/docs/index.md
--- old/micropython-lib-1.27.0/micropython/senml/docs/index.md 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/micropython/senml/docs/index.md 2026-03-23
01:17:33.000000000 +0100
@@ -1,4 +1,4 @@
-Welcome to the API document site for the micro-python SenML library.
+Welcome to the API document site for the MicroPython SenML library.
The following api sections are available:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/python-stdlib/string/manifest.py
new/micropython-lib-1.28.0/python-stdlib/string/manifest.py
--- old/micropython-lib-1.27.0/python-stdlib/string/manifest.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/python-stdlib/string/manifest.py 2026-03-23
01:17:33.000000000 +0100
@@ -1,3 +1,3 @@
-metadata(version="0.1.1")
+metadata(version="0.2.0")
-module("string.py")
+package("string")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/python-stdlib/string/string/__init__.py
new/micropython-lib-1.28.0/python-stdlib/string/string/__init__.py
--- old/micropython-lib-1.27.0/python-stdlib/string/string/__init__.py
1970-01-01 01:00:00.000000000 +0100
+++ new/micropython-lib-1.28.0/python-stdlib/string/string/__init__.py
2026-03-23 01:17:33.000000000 +0100
@@ -0,0 +1,27 @@
+# Some strings for ctype-style character classification
+whitespace = " \t\n\r\v\f"
+ascii_lowercase = "abcdefghijklmnopqrstuvwxyz"
+ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ascii_letters = ascii_lowercase + ascii_uppercase
+digits = "0123456789"
+hexdigits = digits + "abcdef" + "ABCDEF"
+octdigits = "01234567"
+punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
+printable = digits + ascii_letters + punctuation + whitespace
+
+
+def translate(s, map):
+ import io
+
+ sb = io.StringIO()
+ for c in s:
+ v = ord(c)
+ if v in map:
+ v = map[v]
+ if isinstance(v, int):
+ sb.write(chr(v))
+ elif v is not None:
+ sb.write(v)
+ else:
+ sb.write(c)
+ return sb.getvalue()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/python-stdlib/string/string/templatelib.py
new/micropython-lib-1.28.0/python-stdlib/string/string/templatelib.py
--- old/micropython-lib-1.27.0/python-stdlib/string/string/templatelib.py
1970-01-01 01:00:00.000000000 +0100
+++ new/micropython-lib-1.28.0/python-stdlib/string/string/templatelib.py
2026-03-23 01:17:33.000000000 +0100
@@ -0,0 +1,5 @@
+# Import built-in t-string classes if they exist.
+try:
+ from ustring.templatelib import *
+except:
+ pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/python-stdlib/string/string.py
new/micropython-lib-1.28.0/python-stdlib/string/string.py
--- old/micropython-lib-1.27.0/python-stdlib/string/string.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/python-stdlib/string/string.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,27 +0,0 @@
-# Some strings for ctype-style character classification
-whitespace = " \t\n\r\v\f"
-ascii_lowercase = "abcdefghijklmnopqrstuvwxyz"
-ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-ascii_letters = ascii_lowercase + ascii_uppercase
-digits = "0123456789"
-hexdigits = digits + "abcdef" + "ABCDEF"
-octdigits = "01234567"
-punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
-printable = digits + ascii_letters + punctuation + whitespace
-
-
-def translate(s, map):
- import io
-
- sb = io.StringIO()
- for c in s:
- v = ord(c)
- if v in map:
- v = map[v]
- if isinstance(v, int):
- sb.write(chr(v))
- elif v is not None:
- sb.write(v)
- else:
- sb.write(c)
- return sb.getvalue()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/micropython-lib-1.27.0/unix-ffi/_libc/_libc.py
new/micropython-lib-1.28.0/unix-ffi/_libc/_libc.py
--- old/micropython-lib-1.27.0/unix-ffi/_libc/_libc.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/_libc/_libc.py 2026-03-23
01:17:33.000000000 +0100
@@ -4,7 +4,7 @@
_h = None
-names = ("libc.so", "libc.so.0", "libc.so.6", "libc.dylib")
+names = ("libc.so", "libc.so.0", "libc.so.6", "libc.so.7", "libc.dylib")
def get():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/micropython-lib-1.27.0/unix-ffi/_libc/manifest.py
new/micropython-lib-1.28.0/unix-ffi/_libc/manifest.py
--- old/micropython-lib-1.27.0/unix-ffi/_libc/manifest.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/_libc/manifest.py 2026-03-23
01:17:33.000000000 +0100
@@ -1,6 +1,6 @@
metadata(
description="MicroPython FFI helper module (deprecated, replaced by
micropython-ffilib).",
- version="0.3.1",
+ version="0.4.0",
)
# Originally written by Paul Sokolovsky.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/micropython-lib-1.27.0/unix-ffi/machine/machine/__init__.py
new/micropython-lib-1.28.0/unix-ffi/machine/machine/__init__.py
--- old/micropython-lib-1.27.0/unix-ffi/machine/machine/__init__.py
2025-12-08 01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/machine/machine/__init__.py
2026-03-23 01:17:33.000000000 +0100
@@ -4,4 +4,13 @@
def unique_id():
+ for base in ("/etc", "/var/lib/dbus"):
+ try:
+ with open(base + "/machine-id", "rb") as source:
+ data = source.read(32)
+ if len(data) == 32:
+ # unhexlify might not be available
+ return bytes([int(data[i : i + 2], 16) for i in range(0,
32, 2)])
+ except OSError as e:
+ pass
return b"upy-non-unique"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/micropython-lib-1.27.0/unix-ffi/machine/manifest.py
new/micropython-lib-1.28.0/unix-ffi/machine/manifest.py
--- old/micropython-lib-1.27.0/unix-ffi/machine/manifest.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/machine/manifest.py 2026-03-23
01:17:33.000000000 +0100
@@ -1,4 +1,4 @@
-metadata(version="0.2.2")
+metadata(version="0.2.3")
# Originally written by Paul Sokolovsky.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/micropython-lib-1.27.0/unix-ffi/re/manifest.py
new/micropython-lib-1.28.0/unix-ffi/re/manifest.py
--- old/micropython-lib-1.27.0/unix-ffi/re/manifest.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/re/manifest.py 2026-03-23
01:17:33.000000000 +0100
@@ -1,4 +1,4 @@
-metadata(version="0.2.5")
+metadata(version="0.2.6")
# Originally written by Paul Sokolovsky.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/micropython-lib-1.27.0/unix-ffi/re/re.py
new/micropython-lib-1.28.0/unix-ffi/re/re.py
--- old/micropython-lib-1.27.0/unix-ffi/re/re.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/re/re.py 2026-03-23
01:17:33.000000000 +0100
@@ -38,6 +38,10 @@
# to -1
PCRE2_ZERO_TERMINATED = -1
+# PCRE2_UNSET is used for offsets of groups that didn't participate in a match
+# It's SIZE_MAX: 0xFFFFFFFF for 32bit, 0xFFFFFFFFFFFFFFFF for 64bit
+PCRE2_UNSET = (1 << (PCRE2_SIZE_SIZE * 8)) - 1
+
IGNORECASE = I = 0x8
MULTILINE = M = 0x400
@@ -62,12 +66,11 @@
if not n:
return self.s[self.offsets[0] : self.offsets[1]]
if len(n) == 1:
- return self.s[self.offsets[n[0] * 2] : self.offsets[n[0] * 2 + 1]]
- return tuple(self.s[self.offsets[i * 2] : self.offsets[i * 2 + 1]] for
i in n)
+ return None if self.offsets[n[0] * 2] == PCRE2_UNSET else
self.s[self.offsets[n[0] * 2] : self.offsets[n[0] * 2 + 1]]
+ return tuple(None if self.offsets[i * 2] == PCRE2_UNSET else
self.s[self.offsets[i * 2] : self.offsets[i * 2 + 1]] for i in n)
def groups(self, default=None):
- assert default is None
- return tuple(self.group(i + 1) for i in range(self.num - 1))
+ return tuple(default if self.offsets[(i + 1) * 2] == PCRE2_UNSET else
self.group(i + 1) for i in range(self.num - 1))
def start(self, n=0):
return self.offsets[n * 2]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/micropython-lib-1.27.0/unix-ffi/re/test_re.py
new/micropython-lib-1.28.0/unix-ffi/re/test_re.py
--- old/micropython-lib-1.27.0/unix-ffi/re/test_re.py 2025-12-08
01:20:11.000000000 +0100
+++ new/micropython-lib-1.28.0/unix-ffi/re/test_re.py 2026-03-23
01:17:33.000000000 +0100
@@ -60,3 +60,9 @@
text = " \thello there\n \t how are you?"
indents = _leading_whitespace_re.findall(text)
assert indents == [" \t", " \t "]
+
+m = re.match(r"(.)?", "")
+assert m.group() == ""
+assert m.group(0, 1) == ("", None)
+assert m.groups() == (None,)
+assert m.groups("default") == ("default",)