mirror of
https://github.com/MikeWang000000/Natter.git
synced 2025-12-24 11:51:05 +08:00
feat: Add support for MicroPython
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.vscode
|
||||
/micropython/build
|
||||
__pycache__
|
||||
119
micropython/Makefile
Normal file
119
micropython/Makefile
Normal file
@@ -0,0 +1,119 @@
|
||||
include deps.mk
|
||||
|
||||
PROG := natter
|
||||
BUILD_DIR := $(CURDIR)/build
|
||||
PATCH_DIR := $(CURDIR)/patch
|
||||
COMP_DIR := $(BUILD_DIR)/compressed
|
||||
MP_TAR := $(BUILD_DIR)/$(MICROPYTHON_TARNAME)
|
||||
MP_SRC := $(BUILD_DIR)/$(MICROPYTHON_DIRNAME)
|
||||
MP_PACTHED := $(MP_SRC)/.patched
|
||||
LXP_TAR := $(BUILD_DIR)/$(LXPACK_TARNAME)
|
||||
LXP_SRC := $(BUILD_DIR)/$(LXPACK_DIRNAME)
|
||||
PROG_BIN := $(BUILD_DIR)/$(PROG)
|
||||
COMP_BIN := $(COMP_DIR)/$(PROG)
|
||||
|
||||
MP_MAKE_EXTRA := \
|
||||
MICROPY_STANDALONE=1 \
|
||||
MICROPY_PY_BTREE=0 \
|
||||
MICROPY_PY_FFI=0 \
|
||||
MICROPY_PY_SSL=0 \
|
||||
MICROPY_PY_TERMIOS=0 \
|
||||
MICROPY_SSL_MBEDTLS=0 \
|
||||
MICROPY_USE_READLINE=0 \
|
||||
MICROPY_VFS_FAT=0 \
|
||||
MICROPY_VFS_LFS1=0 \
|
||||
MICROPY_VFS_LFS2=0 \
|
||||
MICROPY_GIT_TAG='v$(MICROPYTHON_VERSION)-natter' \
|
||||
MICROPY_GIT_HASH='<no hash>' \
|
||||
SOURCE_DATE_EPOCH=0 \
|
||||
HELP_BUILD_ERROR=
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
MP_MAKE_EXTRA := $(MP_MAKE_EXTRA) CROSS_COMPILE='$(CROSS_COMPILE)'
|
||||
endif
|
||||
ifdef DEBUG
|
||||
MP_MAKE_EXTRA := $(MP_MAKE_EXTRA) DEBUG='$(DEBUG)'
|
||||
endif
|
||||
ifdef V
|
||||
MP_MAKE_EXTRA := $(MP_MAKE_EXTRA) V='$(V)'
|
||||
endif
|
||||
|
||||
MP_CFLAGS_EXTRA := \
|
||||
-frandom-seed=natter \
|
||||
-Wdate-time \
|
||||
-Wno-error=clobbered \
|
||||
-DMICROPY_PY_SYS_TRACEBACKLIMIT=1 \
|
||||
-DMICROPY_PY_RE_MATCH_GROUPS=1 \
|
||||
-DMICROPY_PY_RE_MATCH_SPAN_START_END=1 \
|
||||
-DMICROPY_NLR_SETJMP=1
|
||||
|
||||
ifeq ($(findstring m68k,$(shell $(CROSS_COMPILE)gcc -dumpmachine)),m68k)
|
||||
MP_CFLAGS_EXTRA := $(MP_CFLAGS_EXTRA) -malign-int
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC),1)
|
||||
MP_LDFLAGS_EXTRA := -static
|
||||
endif
|
||||
|
||||
all: $(PROG_BIN)
|
||||
|
||||
download: $(MP_TAR) $(LXP_TAR)
|
||||
|
||||
compress: $(COMP_BIN)
|
||||
|
||||
clean:
|
||||
$(RM) -r '$(MP_SRC)' '$(LXP_SRC)' '$(COMP_DIR)' '$(PROG_BIN)'
|
||||
|
||||
distclean:
|
||||
$(RM) -r '$(BUILD_DIR)'
|
||||
|
||||
$(MP_TAR):
|
||||
mkdir -p '$(BUILD_DIR)'
|
||||
curl -Lfo '$@' '$(MICROPYTHON_SRCURL)'
|
||||
echo '$(MICROPYTHON_SHA256) *$@' | sha256sum -c -
|
||||
|
||||
$(LXP_TAR):
|
||||
mkdir -p '$(BUILD_DIR)'
|
||||
curl -Lfo '$@' '$(LXPACK_SRCURL)'
|
||||
echo '$(LXPACK_SHA256) *$@' | sha256sum -c -
|
||||
|
||||
untar: $(MP_TAR) $(LXP_TAR)
|
||||
rm -rf '$(MP_SRC)' '$(LXP_SRC)'
|
||||
cd '$(BUILD_DIR)' && tar xJf '$(MP_TAR)'
|
||||
cd '$(BUILD_DIR)' && tar xJf '$(LXP_TAR)'
|
||||
|
||||
$(MP_PACTHED): $(wildcard $(PATCH_DIR)/*.patch)
|
||||
test -d '$(MP_SRC)' || $(MAKE) untar
|
||||
find '$(MP_SRC)' -type f -name '*.orig' -exec sh -c 'mv "$$1" "$${1%.orig}"' _ {} \;
|
||||
for p in '$(PATCH_DIR)'/*.patch; do \
|
||||
cd '$(MP_SRC)' && patch -bp1 < "$$p"; \
|
||||
done
|
||||
touch '$@'
|
||||
|
||||
patch: $(MP_PACTHED)
|
||||
|
||||
mpy_cross: $(MP_PACTHED)
|
||||
$(MAKE) -C '$(MP_SRC)/mpy-cross' \
|
||||
PROG=mpy-cross \
|
||||
CROSS_COMPILE= \
|
||||
CFLAGS_EXTRA= \
|
||||
LDFLAGS_EXTRA=
|
||||
|
||||
$(PROG_BIN): mpy_cross
|
||||
$(MAKE) -C '$(MP_SRC)/ports/unix' install \
|
||||
VARIANT=standard \
|
||||
BINDIR='$(BUILD_DIR)' \
|
||||
PROG='$(PROG)' \
|
||||
FROZEN_MANIFEST='$(CURDIR)/pymodule/_manifest.py' \
|
||||
USER_C_MODULES='$(CURDIR)/cmodule' \
|
||||
CFLAGS_EXTRA='$(MP_CFLAGS_EXTRA)' \
|
||||
LDFLAGS_EXTRA='$(MP_LDFLAGS_EXTRA)' \
|
||||
$(MP_MAKE_EXTRA)
|
||||
|
||||
$(COMP_BIN): $(PROG_BIN)
|
||||
test -d '$(LXP_SRC)' || $(MAKE) untar
|
||||
$(MAKE) -C '$(LXP_SRC)' install \
|
||||
BINDIR='$(COMP_DIR)' \
|
||||
PAYLOAD='$(PROG_BIN)'
|
||||
|
||||
.PHONY: all download untar patch mpy_cross compress clean
|
||||
3
micropython/cmodule/_posix/micropython.mk
Normal file
3
micropython/cmodule/_posix/micropython.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
UNIXAPI_MOD_DIR := $(USERMOD_DIR)
|
||||
SRC_USERMOD += $(UNIXAPI_MOD_DIR)/mod_posix.c
|
||||
CFLAGS_USERMOD += -I$(UNIXAPI_MOD_DIR)
|
||||
1257
micropython/cmodule/_posix/mod_posix.c
Normal file
1257
micropython/cmodule/_posix/mod_posix.c
Normal file
File diff suppressed because it is too large
Load Diff
11
micropython/deps.mk
Normal file
11
micropython/deps.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
MICROPYTHON_VERSION = 1.26.1
|
||||
MICROPYTHON_DIRNAME = micropython-$(MICROPYTHON_VERSION)
|
||||
MICROPYTHON_TARNAME = $(MICROPYTHON_DIRNAME).tar.xz
|
||||
MICROPYTHON_SRCURL = https://github.com/micropython/micropython/releases/download/v$(MICROPYTHON_VERSION)/$(MICROPYTHON_TARNAME)
|
||||
MICROPYTHON_SHA256 = 12be6514df6272c0fcb328122b534af6b12abdd52435c19f40ee1707cc43ac98
|
||||
|
||||
LXPACK_VERSION = 1.0.0
|
||||
LXPACK_DIRNAME = lxpack-$(LXPACK_VERSION)
|
||||
LXPACK_TARNAME = $(LXPACK_DIRNAME).tar.xz
|
||||
LXPACK_SRCURL = https://github.com/MikeWang000000/lxpack/releases/download/$(LXPACK_VERSION)/$(LXPACK_TARNAME)
|
||||
LXPACK_SHA256 = 639414c7525b40dff12e4791e53e2d8d58d76acb9dc2ea660c371aae8eefe775
|
||||
82
micropython/patch/ports_unix_main_c.patch
Normal file
82
micropython/patch/ports_unix_main_c.patch
Normal file
@@ -0,0 +1,82 @@
|
||||
diff --git a/ports/unix/main.c b/ports/unix/main.c
|
||||
index 530e20a..c926e54 100644
|
||||
--- a/ports/unix/main.c
|
||||
+++ b/ports/unix/main.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
+#include <libgen.h>
|
||||
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
@@ -509,7 +510,25 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
- pre_process_options(argc, argv);
|
||||
+ int disable_natter = 0;
|
||||
+
|
||||
+ size_t argv0_len = strlen(argv[0]);
|
||||
+ char *basebuf = malloc(argv0_len + 1);
|
||||
+ if (!basebuf) {
|
||||
+ perror(argv[0]);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ memcpy(basebuf, argv[0], argv0_len + 1);
|
||||
+ char *progname = basename(basebuf);
|
||||
+ if (strncmp(progname, "micropython", strlen("micropython")) == 0 ||
|
||||
+ strncmp(progname, "python", strlen("python")) == 0) {
|
||||
+ disable_natter = 1;
|
||||
+ }
|
||||
+ free(basebuf);
|
||||
+
|
||||
+ if (disable_natter) {
|
||||
+ pre_process_options(argc, argv);
|
||||
+ }
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
#if !MICROPY_GC_SPLIT_HEAP
|
||||
@@ -643,7 +662,41 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
const int NOTHING_EXECUTED = -2;
|
||||
int ret = NOTHING_EXECUTED;
|
||||
bool inspect = false;
|
||||
- for (int a = 1; a < argc; a++) {
|
||||
+
|
||||
+ if (!disable_natter) {
|
||||
+ // Run Natter from frozen module 'natter'.
|
||||
+ mp_sys_path = mp_obj_new_list(0, NULL);
|
||||
+ #ifdef MICROPY_MODULE_FROZEN
|
||||
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
|
||||
+ #endif
|
||||
+
|
||||
+ mp_obj_t import_args[4];
|
||||
+ import_args[0] = MP_OBJ_NEW_QSTR(MP_QSTR_natter);
|
||||
+ import_args[1] = mp_const_none;
|
||||
+ import_args[2] = mp_const_none;
|
||||
+ import_args[3] = mp_const_false;
|
||||
+ set_sys_argv(argv, argc, 0);
|
||||
+
|
||||
+ #if MICROPY_GC_ALLOC_THRESHOLD
|
||||
+ MP_STATE_MEM(gc_alloc_threshold) = 8 * 1024 * 1024 /
|
||||
+ MICROPY_BYTES_PER_GC_BLOCK;
|
||||
+ #endif
|
||||
+
|
||||
+ mp_hal_set_interrupt_char(CHAR_CTRL_C);
|
||||
+ nlr_buf_t nlr;
|
||||
+ if (nlr_push(&nlr) == 0) {
|
||||
+ mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args);
|
||||
+ mp_hal_set_interrupt_char(-1);
|
||||
+ mp_handle_pending(true);
|
||||
+ nlr_pop();
|
||||
+ ret = 0;
|
||||
+ } else {
|
||||
+ // uncaught exception
|
||||
+ mp_hal_set_interrupt_char(-1);
|
||||
+ mp_handle_pending(false);
|
||||
+ ret = handle_uncaught_exception(nlr.ret_val) & 0xff;
|
||||
+ }
|
||||
+ } else for (volatile int a = 1; a < argc; a++) {
|
||||
if (argv[a][0] == '-') {
|
||||
if (strcmp(argv[a], "-i") == 0) {
|
||||
inspect = true;
|
||||
19
micropython/patch/py_moderrno_c.patch
Normal file
19
micropython/patch/py_moderrno_c.patch
Normal file
@@ -0,0 +1,19 @@
|
||||
diff --git a/py/moderrno.c b/py/moderrno.c
|
||||
index 58a141c1..995086db 100644
|
||||
--- a/py/moderrno.c
|
||||
+++ b/py/moderrno.c
|
||||
@@ -102,6 +102,14 @@ const mp_obj_module_t mp_module_errno = {
|
||||
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_errno, mp_module_errno);
|
||||
|
||||
qstr mp_errno_to_str(mp_obj_t errno_val) {
|
||||
+ // Query strerror() first to get a human-readable message
|
||||
+ mp_int_t errno_int;
|
||||
+ if (mp_obj_get_int_maybe(errno_val, &errno_int)) {
|
||||
+ char *msg = strerror(errno_int);
|
||||
+ if (msg) {
|
||||
+ return qstr_from_str(msg);
|
||||
+ }
|
||||
+ }
|
||||
#if MICROPY_PY_ERRNO_ERRORCODE
|
||||
// We have the errorcode dict so can do a lookup using the hash map
|
||||
mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP);
|
||||
255
micropython/pymodule/LICENSE.cpython
Normal file
255
micropython/pymodule/LICENSE.cpython
Normal file
@@ -0,0 +1,255 @@
|
||||
A. HISTORY OF THE SOFTWARE
|
||||
==========================
|
||||
|
||||
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
|
||||
as a successor of a language called ABC. Guido remains Python's
|
||||
principal author, although it includes many contributions from others.
|
||||
|
||||
In 1995, Guido continued his work on Python at the Corporation for
|
||||
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
|
||||
in Reston, Virginia where he released several versions of the
|
||||
software.
|
||||
|
||||
In May 2000, Guido and the Python core development team moved to
|
||||
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||
year, the PythonLabs team moved to Digital Creations (now Zope
|
||||
Corporation, see http://www.zope.com). In 2001, the Python Software
|
||||
Foundation (PSF, see http://www.python.org/psf/) was formed, a
|
||||
non-profit organization created specifically to own Python-related
|
||||
Intellectual Property. Zope Corporation is a sponsoring member of
|
||||
the PSF.
|
||||
|
||||
All Python releases are Open Source (see http://www.opensource.org for
|
||||
the Open Source Definition). Historically, most, but not all, Python
|
||||
releases have also been GPL-compatible; the table below summarizes
|
||||
the various releases.
|
||||
|
||||
Release Derived Year Owner GPL-
|
||||
from compatible? (1)
|
||||
|
||||
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||
1.6 1.5.2 2000 CNRI no
|
||||
2.0 1.6 2000 BeOpen.com no
|
||||
1.6.1 1.6 2001 CNRI yes (2)
|
||||
2.1 2.0+1.6.1 2001 PSF no
|
||||
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||
2.1.2 2.1.1 2002 PSF yes
|
||||
2.1.3 2.1.2 2002 PSF yes
|
||||
2.2 and above 2.1.1 2001-now PSF yes
|
||||
|
||||
Footnotes:
|
||||
|
||||
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||
a modified version without making your changes open source. The
|
||||
GPL-compatible licenses make it possible to combine Python with
|
||||
other software that is released under the GPL; the others don't.
|
||||
|
||||
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||
because its license has a choice of law clause. According to
|
||||
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||
is "not incompatible" with the GPL.
|
||||
|
||||
Thanks to the many outside volunteers who have worked under Guido's
|
||||
direction to make these releases possible.
|
||||
|
||||
|
||||
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||
===============================================================
|
||||
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
||||
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software
|
||||
Foundation; All Rights Reserved" are retained in Python alone or in any
|
||||
derivative version prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||
-------------------------------------------
|
||||
|
||||
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||
|
||||
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||
Individual or Organization ("Licensee") accessing and otherwise using
|
||||
this software in source or binary form and its associated
|
||||
documentation ("the Software").
|
||||
|
||||
2. Subject to the terms and conditions of this BeOpen Python License
|
||||
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||
and/or display publicly, prepare derivative works, distribute, and
|
||||
otherwise use the Software alone or in any derivative version,
|
||||
provided, however, that the BeOpen Python License is retained in the
|
||||
Software, alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
5. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
6. This License Agreement shall be governed by and interpreted in all
|
||||
respects by the law of the State of California, excluding conflict of
|
||||
law provisions. Nothing in this License Agreement shall be deemed to
|
||||
create any relationship of agency, partnership, or joint venture
|
||||
between BeOpen and Licensee. This License Agreement does not grant
|
||||
permission to use BeOpen trademarks or trade names in a trademark
|
||||
sense to endorse or promote products or services of Licensee, or any
|
||||
third party. As an exception, the "BeOpen Python" logos available at
|
||||
http://www.pythonlabs.com/logos.html may be used according to the
|
||||
permissions granted on that web page.
|
||||
|
||||
7. By copying, installing or otherwise using the software, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||
---------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||
source or binary form and its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||
license to reproduce, analyze, test, perform and/or display publicly,
|
||||
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||
alone or in any derivative version, provided, however, that CNRI's
|
||||
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||
Agreement, Licensee may substitute the following text (omitting the
|
||||
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||
conditions in CNRI's License Agreement. This Agreement together with
|
||||
Python 1.6.1 may be located on the Internet using the following
|
||||
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||
Agreement may also be obtained from a proxy server on the Internet
|
||||
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python 1.6.1.
|
||||
|
||||
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. This License Agreement shall be governed by the federal
|
||||
intellectual property law of the United States, including without
|
||||
limitation the federal copyright law, and, to the extent such
|
||||
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||
Virginia, excluding Virginia's conflict of law provisions.
|
||||
Notwithstanding the foregoing, with regard to derivative works based
|
||||
on Python 1.6.1 that incorporate non-separable material that was
|
||||
previously distributed under the GNU General Public License (GPL), the
|
||||
law of the Commonwealth of Virginia shall govern this License
|
||||
Agreement only as to issues arising under or with respect to
|
||||
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||
License Agreement shall be deemed to create any relationship of
|
||||
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||
License Agreement does not grant permission to use CNRI trademarks or
|
||||
trade name in a trademark sense to endorse or promote products or
|
||||
services of Licensee, or any third party.
|
||||
|
||||
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||
bound by the terms and conditions of this License Agreement.
|
||||
|
||||
ACCEPT
|
||||
|
||||
|
||||
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||
--------------------------------------------------
|
||||
|
||||
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||
The Netherlands. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
13
micropython/pymodule/_manifest.py
Normal file
13
micropython/pymodule/_manifest.py
Normal file
@@ -0,0 +1,13 @@
|
||||
def __manifest_add_modules():
|
||||
import os
|
||||
for name in os.listdir('.'):
|
||||
if name.endswith('.py') and \
|
||||
not name.startswith('.') and \
|
||||
not name.startswith('_'):
|
||||
module(name)
|
||||
|
||||
|
||||
module('natter.py', base_path='../..')
|
||||
__manifest_add_modules()
|
||||
|
||||
del __manifest_add_modules
|
||||
2428
micropython/pymodule/argparse.py
Normal file
2428
micropython/pymodule/argparse.py
Normal file
File diff suppressed because it is too large
Load Diff
43
micropython/pymodule/atexit.py
Normal file
43
micropython/pymodule/atexit.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# This module provides partial functionality of the CPython "atexit" module for
|
||||
# MicroPython.
|
||||
|
||||
import sys as _usys
|
||||
|
||||
__all__ = [
|
||||
'register', 'unregister'
|
||||
]
|
||||
|
||||
|
||||
class _AtExit(object):
|
||||
def __init__(self):
|
||||
self.regs = []
|
||||
_usys.atexit(self._onexit)
|
||||
|
||||
def register(self, func, *args, **kwargs):
|
||||
self.regs.append((func, args, kwargs))
|
||||
return func
|
||||
|
||||
def unregister(self, func):
|
||||
regs_new = []
|
||||
for reg in self.regs:
|
||||
if reg[0] != func:
|
||||
regs_new.append(reg)
|
||||
self.regs = regs_new
|
||||
|
||||
def _onexit(self):
|
||||
last_ex = None
|
||||
for func, args, kwargs in reversed(self.regs):
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
except Exception as ex:
|
||||
last_ex = ex
|
||||
_usys.print_exception(ex, _usys.stderr)
|
||||
|
||||
if last_ex:
|
||||
raise last_ex from None
|
||||
|
||||
|
||||
_atexit = _AtExit()
|
||||
|
||||
register = _atexit.register
|
||||
unregister = _atexit.unregister
|
||||
38
micropython/pymodule/codecs.py
Normal file
38
micropython/pymodule/codecs.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# This module provides partial functionality of the CPython "codecs" module for
|
||||
# MicroPython.
|
||||
|
||||
__all__ = [
|
||||
'CodecInfo', 'lookup', 'register', 'ascii_encode', 'ascii_decode'
|
||||
]
|
||||
|
||||
|
||||
class CodecInfo(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
_dummy = CodecInfo()
|
||||
|
||||
|
||||
def lookup(encoding):
|
||||
return _dummy
|
||||
|
||||
|
||||
def register(search_function):
|
||||
pass
|
||||
|
||||
|
||||
def ascii_encode(string, errors=None):
|
||||
if errors is not None:
|
||||
data = string.encode('ascii', errors)
|
||||
else:
|
||||
data = string.encode('ascii')
|
||||
return data, len(data)
|
||||
|
||||
|
||||
def ascii_decode(data, errors=None):
|
||||
if errors is not None:
|
||||
string = data.decode('ascii', errors)
|
||||
else:
|
||||
string = data.decode('ascii')
|
||||
return string, len(string)
|
||||
93
micropython/pymodule/errno.py
Normal file
93
micropython/pymodule/errno.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# This module provides partial functionality of the CPython "errno" module for
|
||||
# MicroPython.
|
||||
|
||||
import _posix
|
||||
|
||||
E2BIG = _posix.E2BIG
|
||||
EACCES = _posix.EACCES
|
||||
EADDRINUSE = _posix.EADDRINUSE
|
||||
EADDRNOTAVAIL = _posix.EADDRNOTAVAIL
|
||||
EAFNOSUPPORT = _posix.EAFNOSUPPORT
|
||||
EAGAIN = _posix.EAGAIN
|
||||
EALREADY = _posix.EALREADY
|
||||
EBADF = _posix.EBADF
|
||||
EBADMSG = _posix.EBADMSG
|
||||
EBUSY = _posix.EBUSY
|
||||
ECANCELED = _posix.ECANCELED
|
||||
ECHILD = _posix.ECHILD
|
||||
ECONNABORTED = _posix.ECONNABORTED
|
||||
ECONNREFUSED = _posix.ECONNREFUSED
|
||||
ECONNRESET = _posix.ECONNRESET
|
||||
EDEADLK = _posix.EDEADLK
|
||||
EDESTADDRREQ = _posix.EDESTADDRREQ
|
||||
EDOM = _posix.EDOM
|
||||
EDQUOT = _posix.EDQUOT
|
||||
EEXIST = _posix.EEXIST
|
||||
EFAULT = _posix.EFAULT
|
||||
EFBIG = _posix.EFBIG
|
||||
EHOSTUNREACH = _posix.EHOSTUNREACH
|
||||
EIDRM = _posix.EIDRM
|
||||
EILSEQ = _posix.EILSEQ
|
||||
EINPROGRESS = _posix.EINPROGRESS
|
||||
EINTR = _posix.EINTR
|
||||
EINVAL = _posix.EINVAL
|
||||
EIO = _posix.EIO
|
||||
EISCONN = _posix.EISCONN
|
||||
EISDIR = _posix.EISDIR
|
||||
ELOOP = _posix.ELOOP
|
||||
EMFILE = _posix.EMFILE
|
||||
EMLINK = _posix.EMLINK
|
||||
EMSGSIZE = _posix.EMSGSIZE
|
||||
EMULTIHOP = _posix.EMULTIHOP
|
||||
ENAMETOOLONG = _posix.ENAMETOOLONG
|
||||
ENETDOWN = _posix.ENETDOWN
|
||||
ENETRESET = _posix.ENETRESET
|
||||
ENETUNREACH = _posix.ENETUNREACH
|
||||
ENFILE = _posix.ENFILE
|
||||
ENOBUFS = _posix.ENOBUFS
|
||||
ENODATA = _posix.ENODATA
|
||||
ENODEV = _posix.ENODEV
|
||||
ENOENT = _posix.ENOENT
|
||||
ENOEXEC = _posix.ENOEXEC
|
||||
ENOLCK = _posix.ENOLCK
|
||||
ENOLINK = _posix.ENOLINK
|
||||
ENOMEM = _posix.ENOMEM
|
||||
ENOMSG = _posix.ENOMSG
|
||||
ENOPROTOOPT = _posix.ENOPROTOOPT
|
||||
ENOSPC = _posix.ENOSPC
|
||||
ENOSR = _posix.ENOSR
|
||||
ENOSTR = _posix.ENOSTR
|
||||
ENOSYS = _posix.ENOSYS
|
||||
ENOTCONN = _posix.ENOTCONN
|
||||
ENOTDIR = _posix.ENOTDIR
|
||||
ENOTEMPTY = _posix.ENOTEMPTY
|
||||
ENOTRECOVERABLE = _posix.ENOTRECOVERABLE
|
||||
ENOTSOCK = _posix.ENOTSOCK
|
||||
ENOTSUP = _posix.ENOTSUP
|
||||
ENOTTY = _posix.ENOTTY
|
||||
ENXIO = _posix.ENXIO
|
||||
EOPNOTSUPP = _posix.EOPNOTSUPP
|
||||
EOVERFLOW = _posix.EOVERFLOW
|
||||
EOWNERDEAD = _posix.EOWNERDEAD
|
||||
EPERM = _posix.EPERM
|
||||
EPIPE = _posix.EPIPE
|
||||
EPROTO = _posix.EPROTO
|
||||
EPROTONOSUPPORT = _posix.EPROTONOSUPPORT
|
||||
EPROTOTYPE = _posix.EPROTOTYPE
|
||||
ERANGE = _posix.ERANGE
|
||||
EROFS = _posix.EROFS
|
||||
ESPIPE = _posix.ESPIPE
|
||||
ESRCH = _posix.ESRCH
|
||||
ESTALE = _posix.ESTALE
|
||||
ETIME = _posix.ETIME
|
||||
ETIMEDOUT = _posix.ETIMEDOUT
|
||||
ETXTBSY = _posix.ETXTBSY
|
||||
EWOULDBLOCK = _posix.EWOULDBLOCK
|
||||
EXDEV = _posix.EXDEV
|
||||
|
||||
|
||||
errorcode = dict()
|
||||
|
||||
for name, value in locals().items():
|
||||
if name.startswith('E') and isinstance(value, int):
|
||||
errorcode[value] = name
|
||||
134
micropython/pymodule/genericpath.py
Normal file
134
micropython/pymodule/genericpath.py
Normal file
@@ -0,0 +1,134 @@
|
||||
# Modified from CPython 3.4.10 "genericpath" module for MicroPython
|
||||
|
||||
"""
|
||||
Path operations common to more than one OS
|
||||
Do not use directly. The OS specific modules import the appropriate
|
||||
functions from this module themselves.
|
||||
"""
|
||||
import _posix
|
||||
import os as _zos
|
||||
|
||||
__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',
|
||||
'getsize', 'isdir', 'isfile', 'samefile', 'sameopenfile',
|
||||
'samestat']
|
||||
|
||||
|
||||
# Does a path exist?
|
||||
# This is false for dangling symbolic links on systems that support them.
|
||||
def exists(path):
|
||||
"""Test whether a path exists. Returns False for broken symbolic links"""
|
||||
try:
|
||||
_zos.stat(path)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# This follows symbolic links, so both islink() and isdir() can be true
|
||||
# for the same path on systems that support symlinks
|
||||
def isfile(path):
|
||||
"""Test whether a path is a regular file"""
|
||||
try:
|
||||
st = _zos.stat(path)
|
||||
except OSError:
|
||||
return False
|
||||
return _posix.S_ISREG(st.st_mode)
|
||||
|
||||
|
||||
# Is a path a directory?
|
||||
# This follows symbolic links, so both islink() and isdir()
|
||||
# can be true for the same path on systems that support symlinks
|
||||
def isdir(s):
|
||||
"""Return true if the pathname refers to an existing directory."""
|
||||
try:
|
||||
st = _zos.stat(s)
|
||||
except OSError:
|
||||
return False
|
||||
return _posix.S_ISDIR(st.st_mode)
|
||||
|
||||
|
||||
def getsize(filename):
|
||||
"""Return the size of a file, reported by os.stat()."""
|
||||
return _zos.stat(filename).st_size
|
||||
|
||||
|
||||
def getmtime(filename):
|
||||
"""Return the last modification time of a file, reported by os.stat()."""
|
||||
return _zos.stat(filename).st_mtime
|
||||
|
||||
|
||||
def getatime(filename):
|
||||
"""Return the last access time of a file, reported by os.stat()."""
|
||||
return _zos.stat(filename).st_atime
|
||||
|
||||
|
||||
def getctime(filename):
|
||||
"""Return the metadata change time of a file, reported by os.stat()."""
|
||||
return _zos.stat(filename).st_ctime
|
||||
|
||||
|
||||
# Return the longest prefix of all list elements.
|
||||
def commonprefix(m):
|
||||
"Given a list of pathnames, returns the longest common leading component"
|
||||
if not m: return ''
|
||||
s1 = min(m)
|
||||
s2 = max(m)
|
||||
for i, c in enumerate(s1):
|
||||
if c != s2[i]:
|
||||
return s1[:i]
|
||||
return s1
|
||||
|
||||
# Are two stat buffers (obtained from stat, fstat or lstat)
|
||||
# describing the same file?
|
||||
def samestat(s1, s2):
|
||||
"""Test whether two stat buffers reference the same file"""
|
||||
return (s1.st_ino == s2.st_ino and
|
||||
s1.st_dev == s2.st_dev)
|
||||
|
||||
|
||||
# Are two filenames really pointing to the same file?
|
||||
def samefile(f1, f2):
|
||||
"""Test whether two pathnames reference the same actual file"""
|
||||
s1 = _zos.stat(f1)
|
||||
s2 = _zos.stat(f2)
|
||||
return samestat(s1, s2)
|
||||
|
||||
|
||||
# Are two open files really referencing the same file?
|
||||
# (Not necessarily the same file descriptor!)
|
||||
def sameopenfile(fp1, fp2):
|
||||
"""Test whether two open file objects reference the same file"""
|
||||
s1 = _zos.fstat(fp1)
|
||||
s2 = _zos.fstat(fp2)
|
||||
return samestat(s1, s2)
|
||||
|
||||
|
||||
# Split a path in root and extension.
|
||||
# The extension is everything starting at the last dot in the last
|
||||
# pathname component; the root is everything before that.
|
||||
# It is always true that root + ext == p.
|
||||
|
||||
# Generic implementation of splitext, to be parametrized with
|
||||
# the separators
|
||||
def _splitext(p, sep, altsep, extsep):
|
||||
"""Split the extension from a pathname.
|
||||
|
||||
Extension is everything from the last dot to the end, ignoring
|
||||
leading dots. Returns "(root, ext)"; ext may be empty."""
|
||||
# NOTE: This code must work for text and bytes strings.
|
||||
|
||||
sepIndex = p.rfind(sep)
|
||||
if altsep:
|
||||
altsepIndex = p.rfind(altsep)
|
||||
sepIndex = max(sepIndex, altsepIndex)
|
||||
|
||||
dotIndex = p.rfind(extsep)
|
||||
if dotIndex > sepIndex:
|
||||
# skip all leading dots
|
||||
filenameIndex = sepIndex + 1
|
||||
while filenameIndex < dotIndex:
|
||||
if p[filenameIndex:filenameIndex+1] != extsep:
|
||||
return p[:dotIndex], p[dotIndex:]
|
||||
filenameIndex += 1
|
||||
|
||||
return p, p[:0]
|
||||
163
micropython/pymodule/os.py
Normal file
163
micropython/pymodule/os.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# This module provides partial functionality of the CPython "os" module for
|
||||
# MicroPython.
|
||||
|
||||
import sys as _sys
|
||||
_path = _sys.path
|
||||
_sys.path = ()
|
||||
try:
|
||||
import os as _uos
|
||||
finally:
|
||||
_sys.path = _path
|
||||
del _path
|
||||
|
||||
import _posix
|
||||
import posixpath as path
|
||||
|
||||
__all__ = [
|
||||
'_Environ', 'altsep', 'chdir', 'curdir', 'defpath', 'devnull', 'environ',
|
||||
'extsep', 'getcwd', 'getcwdb', 'getenv', 'linesep', 'listdir', 'lstat',
|
||||
'mkdir', 'mount', 'name', 'pardir', 'path', 'pathsep', 'putenv', 'remove',
|
||||
'rename', 'rmdir', 'sep', 'stat', 'stat_result', 'system', 'umount',
|
||||
'uname', 'uname_result', 'unlink', 'unsetenv', 'urandom'
|
||||
]
|
||||
|
||||
|
||||
class _Environ(dict):
|
||||
def __setitem__(self, key, value):
|
||||
_uos.putenv(key, value)
|
||||
super().__setitem__(key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
_uos.unsetenv(key)
|
||||
super().__delitem__(key)
|
||||
|
||||
def __repr__(self):
|
||||
return 'environ({%s})' % (
|
||||
', '.join(
|
||||
'%s: %s' % (repr(key), repr(value))
|
||||
for key, value in self.items()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _createenviron():
|
||||
envdict = dict()
|
||||
envlist = _posix._environ()
|
||||
for env in envlist:
|
||||
kv = env.split('=', 1)
|
||||
if len(kv) < 2:
|
||||
envdict[kv[0]] = ''
|
||||
else:
|
||||
envdict[kv[0]] = kv[1]
|
||||
return _Environ(envdict)
|
||||
|
||||
|
||||
# unicode environ
|
||||
environ = _createenviron()
|
||||
|
||||
|
||||
del _createenviron
|
||||
|
||||
|
||||
class stat_result(tuple):
|
||||
# MicroPython note:
|
||||
# tuple subclass data is passed to __init__ in MicroPython, not __new__,
|
||||
# so attributes are set here.
|
||||
def __init__(self, t):
|
||||
super().__init__(t)
|
||||
self.st_mode = t[0]
|
||||
self.st_ino = t[1]
|
||||
self.st_dev = t[2]
|
||||
self.st_nlink = t[3]
|
||||
self.st_uid = t[4]
|
||||
self.st_gid = t[5]
|
||||
self.st_size = t[6]
|
||||
self.st_atime = t[7]
|
||||
self.st_mtime = t[8]
|
||||
self.st_ctime = t[9]
|
||||
self.__frozen__ = True
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if hasattr(self, '__frozen__') and self.__frozen__:
|
||||
raise AttributeError("Assignment is not allowed")
|
||||
|
||||
def __repr__(self):
|
||||
return "stat_result(%s)" % repr(super())
|
||||
|
||||
|
||||
class uname_result(tuple):
|
||||
# MicroPython note:
|
||||
# tuple subclass data is passed to __init__ in MicroPython, not __new__,
|
||||
# so attributes are set here.
|
||||
def __init__(self, t):
|
||||
super().__init__(t)
|
||||
self.sysname = t[0]
|
||||
self.nodename = t[1]
|
||||
self.release = t[2]
|
||||
self.version = t[3]
|
||||
self.machine = t[4]
|
||||
self.__frozen__ = True
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if hasattr(self, '__frozen__') and self.__frozen__:
|
||||
raise AttributeError("Assignment is not allowed")
|
||||
|
||||
def __repr__(self):
|
||||
return "uname_result(%s)" % repr(super())
|
||||
|
||||
|
||||
name = 'posix'
|
||||
linesep = '\n'
|
||||
curdir = path.curdir
|
||||
pardir = path.pardir
|
||||
extsep = path.extsep
|
||||
sep = path.sep
|
||||
pathsep = path.pathsep
|
||||
defpath = path.defpath
|
||||
altsep = path.altsep
|
||||
devnull = path.devnull
|
||||
|
||||
chdir = _uos.chdir
|
||||
getcwd = _uos.getcwd
|
||||
listdir = _uos.listdir
|
||||
mkdir = _uos.mkdir
|
||||
mount = _uos.mount
|
||||
putenv = _uos.putenv
|
||||
remove = _uos.remove
|
||||
rename = _uos.rename
|
||||
rmdir = _uos.rmdir
|
||||
system = _uos.system
|
||||
umount = _uos.umount
|
||||
unlink = _uos.unlink
|
||||
unsetenv = _uos.unsetenv
|
||||
urandom = _uos.urandom
|
||||
|
||||
isatty = _posix.isatty
|
||||
getuid = _posix.getuid
|
||||
|
||||
|
||||
def getcwdb():
|
||||
return _uos.getcwd().encode()
|
||||
|
||||
|
||||
def getenv(key, default=None):
|
||||
return _uos.getenv(key, default)
|
||||
|
||||
|
||||
def stat(path):
|
||||
result = _posix.stat(path)
|
||||
return stat_result(result)
|
||||
|
||||
|
||||
def lstat(path):
|
||||
result = _posix.lstat(path)
|
||||
return stat_result(result)
|
||||
|
||||
|
||||
def uname():
|
||||
result = _posix.uname()
|
||||
return uname_result(result)
|
||||
|
||||
|
||||
def strerror(code):
|
||||
return _posix.strerror(code)
|
||||
361
micropython/pymodule/posixpath.py
Normal file
361
micropython/pymodule/posixpath.py
Normal file
@@ -0,0 +1,361 @@
|
||||
# Modified from CPython 3.4.10 "posixpath" module for MicroPython
|
||||
|
||||
"""Common operations on Posix pathnames.
|
||||
|
||||
Instead of importing this module directly, import os and refer to
|
||||
this module as os.path. The "os.path" name is an alias for this
|
||||
module on Posix systems; on other systems (e.g. Mac, Windows),
|
||||
os.path provides the same operations in a manner specific to that
|
||||
platform, and is an alias to another module (e.g. macpath, ntpath).
|
||||
|
||||
Some of this can actually be useful on non-Posix systems too, e.g.
|
||||
for manipulation of the pathname component of URLs.
|
||||
"""
|
||||
|
||||
import sys as _usys
|
||||
import _posix
|
||||
import os as _zos
|
||||
import genericpath as _zgenericpath
|
||||
from genericpath import *
|
||||
|
||||
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
|
||||
"basename","dirname","commonprefix","getsize","getmtime",
|
||||
"getatime","getctime","islink","exists","lexists","isdir","isfile",
|
||||
"ismount", "normpath","abspath", "samefile","sameopenfile",
|
||||
"samestat","curdir","pardir","sep","pathsep","defpath","altsep",
|
||||
"extsep","devnull","realpath","supports_unicode_filenames",
|
||||
"relpath"]
|
||||
|
||||
# Strings representing various path-related bits and pieces.
|
||||
# These are primarily for export; internally, they are hardcoded.
|
||||
curdir = '.'
|
||||
pardir = '..'
|
||||
extsep = '.'
|
||||
sep = '/'
|
||||
pathsep = ':'
|
||||
defpath = ':/bin:/usr/bin'
|
||||
altsep = None
|
||||
devnull = '/dev/null'
|
||||
|
||||
def _get_sep(path):
|
||||
if isinstance(path, bytes):
|
||||
return b'/'
|
||||
else:
|
||||
return '/'
|
||||
|
||||
# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
|
||||
# On MS-DOS this may also turn slashes into backslashes; however, other
|
||||
# normalizations (such as optimizing '../' away) are not allowed
|
||||
# (another function should be defined to do that).
|
||||
|
||||
def normcase(s):
|
||||
"""Normalize case of pathname. Has no effect under Posix"""
|
||||
if not isinstance(s, (bytes, str)):
|
||||
raise TypeError("normcase() argument must be str or bytes, "
|
||||
"not '{}'".format(s.__class__.__name__))
|
||||
return s
|
||||
|
||||
|
||||
# Return whether a path is absolute.
|
||||
# Trivial in Posix, harder on the Mac or MS-DOS.
|
||||
|
||||
def isabs(s):
|
||||
"""Test whether a path is absolute"""
|
||||
sep = _get_sep(s)
|
||||
return s.startswith(sep)
|
||||
|
||||
|
||||
# Join pathnames.
|
||||
# Ignore the previous parts if a part is absolute.
|
||||
# Insert a '/' unless the first part is empty or already ends in '/'.
|
||||
|
||||
def join(a, *p):
|
||||
"""Join two or more pathname components, inserting '/' as needed.
|
||||
If any component is an absolute path, all previous path components
|
||||
will be discarded. An empty last part will result in a path that
|
||||
ends with a separator."""
|
||||
sep = _get_sep(a)
|
||||
path = a
|
||||
try:
|
||||
for b in p:
|
||||
if b.startswith(sep):
|
||||
path = b
|
||||
elif not path or path.endswith(sep):
|
||||
path += b
|
||||
else:
|
||||
path += sep + b
|
||||
except TypeError:
|
||||
if all(isinstance(s, (str, bytes)) for s in (a,) + p):
|
||||
# Must have a mixture of text and binary data
|
||||
raise TypeError("Can't mix strings and bytes in path "
|
||||
"components") from None
|
||||
raise
|
||||
return path
|
||||
|
||||
|
||||
# Split a path in head (everything up to the last '/') and tail (the
|
||||
# rest). If the path ends in '/', tail will be empty. If there is no
|
||||
# '/' in the path, head will be empty.
|
||||
# Trailing '/'es are stripped from head unless it is the root.
|
||||
|
||||
def split(p):
|
||||
"""Split a pathname. Returns tuple "(head, tail)" where "tail" is
|
||||
everything after the final slash. Either part may be empty."""
|
||||
sep = _get_sep(p)
|
||||
i = p.rfind(sep) + 1
|
||||
head, tail = p[:i], p[i:]
|
||||
if head and head != sep*len(head):
|
||||
head = head.rstrip(sep)
|
||||
return head, tail
|
||||
|
||||
|
||||
# Split a path in root and extension.
|
||||
# The extension is everything starting at the last dot in the last
|
||||
# pathname component; the root is everything before that.
|
||||
# It is always true that root + ext == p.
|
||||
|
||||
def splitext(p):
|
||||
if isinstance(p, bytes):
|
||||
sep = b'/'
|
||||
extsep = b'.'
|
||||
else:
|
||||
sep = '/'
|
||||
extsep = '.'
|
||||
return _zgenericpath._splitext(p, sep, None, extsep)
|
||||
|
||||
|
||||
# Split a pathname into a drive specification and the rest of the
|
||||
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
|
||||
|
||||
def splitdrive(p):
|
||||
"""Split a pathname into drive and path. On Posix, drive is always
|
||||
empty."""
|
||||
return p[:0], p
|
||||
|
||||
|
||||
# Return the tail (basename) part of a path, same as split(path)[1].
|
||||
|
||||
def basename(p):
|
||||
"""Returns the final component of a pathname"""
|
||||
sep = _get_sep(p)
|
||||
i = p.rfind(sep) + 1
|
||||
return p[i:]
|
||||
|
||||
|
||||
# Return the head (dirname) part of a path, same as split(path)[0].
|
||||
|
||||
def dirname(p):
|
||||
"""Returns the directory component of a pathname"""
|
||||
sep = _get_sep(p)
|
||||
i = p.rfind(sep) + 1
|
||||
head = p[:i]
|
||||
if head and head != sep*len(head):
|
||||
head = head.rstrip(sep)
|
||||
return head
|
||||
|
||||
|
||||
# Is a path a symbolic link?
|
||||
# This will always return false on systems where os.lstat doesn't exist.
|
||||
|
||||
def islink(path):
|
||||
"""Test whether a path is a symbolic link"""
|
||||
try:
|
||||
st = _zos.lstat(path)
|
||||
except (OSError, AttributeError):
|
||||
return False
|
||||
return _posix.S_ISLNK(st.st_mode)
|
||||
|
||||
# Being true for dangling symbolic links is also useful.
|
||||
|
||||
def lexists(path):
|
||||
"""Test whether a path exists. Returns True for broken symbolic links"""
|
||||
try:
|
||||
_zos.lstat(path)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Is a path a mount point?
|
||||
# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
|
||||
|
||||
def ismount(path):
|
||||
"""Test whether a path is a mount point"""
|
||||
try:
|
||||
s1 = _zos.lstat(path)
|
||||
except OSError:
|
||||
# It doesn't exist -- so not a mount point. :-)
|
||||
return False
|
||||
else:
|
||||
# A symlink can never be a mount point
|
||||
if _posix.S_ISLNK(s1.st_mode):
|
||||
return False
|
||||
|
||||
if isinstance(path, bytes):
|
||||
parent = join(path, b'..')
|
||||
else:
|
||||
parent = join(path, '..')
|
||||
try:
|
||||
s2 = _zos.lstat(parent)
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
dev1 = s1.st_dev
|
||||
dev2 = s2.st_dev
|
||||
if dev1 != dev2:
|
||||
return True # path/.. on a different device as path
|
||||
ino1 = s1.st_ino
|
||||
ino2 = s2.st_ino
|
||||
if ino1 == ino2:
|
||||
return True # path/.. is the same i-node as path
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
|
||||
# It should be understood that this may change the meaning of the path
|
||||
# if it contains symbolic links!
|
||||
|
||||
def normpath(path):
|
||||
"""Normalize path, eliminating double slashes, etc."""
|
||||
if isinstance(path, bytes):
|
||||
sep = b'/'
|
||||
empty = b''
|
||||
dot = b'.'
|
||||
dotdot = b'..'
|
||||
else:
|
||||
sep = '/'
|
||||
empty = ''
|
||||
dot = '.'
|
||||
dotdot = '..'
|
||||
if path == empty:
|
||||
return dot
|
||||
initial_slashes = path.startswith(sep)
|
||||
# POSIX allows one or two initial slashes, but treats three or more
|
||||
# as single slash.
|
||||
if (initial_slashes and
|
||||
path.startswith(sep*2) and not path.startswith(sep*3)):
|
||||
initial_slashes = 2
|
||||
comps = path.split(sep)
|
||||
new_comps = []
|
||||
for comp in comps:
|
||||
if comp in (empty, dot):
|
||||
continue
|
||||
if (comp != dotdot or (not initial_slashes and not new_comps) or
|
||||
(new_comps and new_comps[-1] == dotdot)):
|
||||
new_comps.append(comp)
|
||||
elif new_comps:
|
||||
new_comps.pop()
|
||||
comps = new_comps
|
||||
path = sep.join(comps)
|
||||
if initial_slashes:
|
||||
path = sep*initial_slashes + path
|
||||
return path or dot
|
||||
|
||||
|
||||
def abspath(path):
|
||||
"""Return an absolute path."""
|
||||
if not isabs(path):
|
||||
if isinstance(path, bytes):
|
||||
cwd = _zos.getcwdb()
|
||||
else:
|
||||
cwd = _zos.getcwd()
|
||||
path = join(cwd, path)
|
||||
return normpath(path)
|
||||
|
||||
|
||||
# Return a canonical path (i.e. the absolute location of a file on the
|
||||
# filesystem).
|
||||
|
||||
def realpath(filename):
|
||||
"""Return the canonical path of the specified filename, eliminating any
|
||||
symbolic links encountered in the path."""
|
||||
path, ok = _joinrealpath(filename[:0], filename, {})
|
||||
return abspath(path)
|
||||
|
||||
# Join two paths, normalizing ang eliminating any symbolic links
|
||||
# encountered in the second path.
|
||||
def _joinrealpath(path, rest, seen):
|
||||
if isinstance(path, bytes):
|
||||
sep = b'/'
|
||||
curdir = b'.'
|
||||
pardir = b'..'
|
||||
else:
|
||||
sep = '/'
|
||||
curdir = '.'
|
||||
pardir = '..'
|
||||
|
||||
if isabs(rest):
|
||||
rest = rest[1:]
|
||||
path = sep
|
||||
|
||||
while rest:
|
||||
name, _, rest = rest.partition(sep)
|
||||
if not name or name == curdir:
|
||||
# current dir
|
||||
continue
|
||||
if name == pardir:
|
||||
# parent dir
|
||||
if path:
|
||||
path, name = split(path)
|
||||
if name == pardir:
|
||||
path = join(path, pardir, pardir)
|
||||
else:
|
||||
path = pardir
|
||||
continue
|
||||
newpath = join(path, name)
|
||||
if not islink(newpath):
|
||||
path = newpath
|
||||
continue
|
||||
# Resolve the symbolic link
|
||||
if newpath in seen:
|
||||
# Already seen this path
|
||||
path = seen[newpath]
|
||||
if path is not None:
|
||||
# use cached value
|
||||
continue
|
||||
# The symlink is not resolved, so we must have a symlink loop.
|
||||
# Return already resolved part + rest of the path unchanged.
|
||||
return join(newpath, rest), False
|
||||
seen[newpath] = None # not resolved symlink
|
||||
linkdst = _posix.readlink(newpath)
|
||||
if isinstance(path, bytes) and isinstance(linkdst, str):
|
||||
linkdst = linkdst.encode()
|
||||
path, ok = _joinrealpath(path, linkdst, seen)
|
||||
if not ok:
|
||||
return join(path, rest), False
|
||||
seen[newpath] = path # resolved symlink
|
||||
|
||||
return path, True
|
||||
|
||||
|
||||
supports_unicode_filenames = (_usys.platform == 'darwin')
|
||||
|
||||
def relpath(path, start=None):
|
||||
"""Return a relative version of a path"""
|
||||
|
||||
if not path:
|
||||
raise ValueError("no path specified")
|
||||
|
||||
if isinstance(path, bytes):
|
||||
curdir = b'.'
|
||||
sep = b'/'
|
||||
pardir = b'..'
|
||||
else:
|
||||
curdir = '.'
|
||||
sep = '/'
|
||||
pardir = '..'
|
||||
|
||||
if start is None:
|
||||
start = curdir
|
||||
|
||||
start_list = [x for x in abspath(start).split(sep) if x]
|
||||
path_list = [x for x in abspath(path).split(sep) if x]
|
||||
|
||||
# Work out how much of the filepath is shared by start and path.
|
||||
i = len(commonprefix([start_list, path_list]))
|
||||
|
||||
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
|
||||
if not rel_list:
|
||||
return curdir
|
||||
return join(*rel_list)
|
||||
138
micropython/pymodule/re.py
Normal file
138
micropython/pymodule/re.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# This module provides partial functionality of the CPython "re" module for
|
||||
# MicroPython.
|
||||
# Notes:
|
||||
# This module uses MicroPython's builtin regex engine "re1.5".
|
||||
# Regular expression syntax supported is a subset of CPython re module.
|
||||
|
||||
import sys as _sys
|
||||
_path = _sys.path
|
||||
_sys.path = ()
|
||||
try:
|
||||
import re as _ure
|
||||
finally:
|
||||
_sys.path = _path
|
||||
del _path
|
||||
|
||||
__all__ = [
|
||||
'Match', 'Pattern', 'compile', 'findall', 'match', 'search', 'split', 'sub'
|
||||
]
|
||||
|
||||
|
||||
_default = object()
|
||||
|
||||
|
||||
class Pattern(object):
|
||||
_Pattern = type(_ure.compile(''))
|
||||
|
||||
def __init__(self, p, pstring, flags):
|
||||
if not isinstance(p, Pattern._Pattern):
|
||||
raise TypeError
|
||||
self._p = p
|
||||
self.pattern = pstring
|
||||
self.flags = flags
|
||||
|
||||
def search(self, string, pos=0, endpos=_default):
|
||||
if endpos is _default:
|
||||
m = self._p.search(string, pos)
|
||||
else:
|
||||
m = self._p.search(string, pos, endpos)
|
||||
if m:
|
||||
return Match(m, self, string)
|
||||
|
||||
def match(self, string, pos=0, endpos=_default):
|
||||
if endpos is _default:
|
||||
m = self._p.match(string, pos)
|
||||
else:
|
||||
m = self._p.match(string, pos, endpos)
|
||||
if m:
|
||||
return Match(m, self, string)
|
||||
|
||||
def split(self, string, maxsplit=0):
|
||||
return self._p.split(string, maxsplit)
|
||||
|
||||
def sub(self, repl, string, count=0):
|
||||
if callable(repl):
|
||||
return self._p.sub(lambda m: repl(Match(m, self, string)), string, count)
|
||||
else:
|
||||
return self._p.sub(repl, string, count)
|
||||
|
||||
def findall(self, string, pos=0, endpos=_default):
|
||||
all = []
|
||||
def cb(m):
|
||||
groups = m.groups()
|
||||
if groups and len(groups) > 2:
|
||||
all.append(groups)
|
||||
else:
|
||||
all.append(m.group(0))
|
||||
return type(m.string)()
|
||||
|
||||
if endpos is not _default:
|
||||
if endpos < pos:
|
||||
endpos = pos
|
||||
if pos < 0:
|
||||
pos = 0
|
||||
string = string[pos:endpos]
|
||||
elif pos > 0:
|
||||
string = string[pos:]
|
||||
self.sub(cb, string)
|
||||
return all
|
||||
|
||||
|
||||
class Match(object):
|
||||
_Match = type(_ure.match('',''))
|
||||
|
||||
def __init__(self, m, re, string):
|
||||
if not isinstance(m, Match._Match):
|
||||
raise TypeError
|
||||
if not isinstance(re, Pattern):
|
||||
raise TypeError
|
||||
self._m = m
|
||||
self.re = re
|
||||
self.string = string
|
||||
|
||||
def group(self, *args):
|
||||
if not args:
|
||||
return self._m.group(0)
|
||||
elif len(args) == 1:
|
||||
return self._m.group(args[0])
|
||||
glist = []
|
||||
for idx in args:
|
||||
glist.append(self._m.group(idx))
|
||||
return tuple(glist)
|
||||
|
||||
def groups(self, default=None):
|
||||
if default is None:
|
||||
return self._m.groups()
|
||||
else:
|
||||
glist = list(self._m.groups())
|
||||
for i, value in enumerate(glist):
|
||||
if value is None:
|
||||
glist[i] = default
|
||||
return tuple(glist)
|
||||
|
||||
|
||||
def compile(pattern, flags=0):
|
||||
if isinstance(pattern, Pattern):
|
||||
return compile(pattern.pattern, flags)
|
||||
p = _ure.compile(pattern, flags)
|
||||
return Pattern(p, pattern, flags)
|
||||
|
||||
|
||||
def search(pattern, string, flags=0):
|
||||
return compile(pattern, flags).search(string)
|
||||
|
||||
|
||||
def match(pattern, string, flags=0):
|
||||
return compile(pattern, flags).match(string)
|
||||
|
||||
|
||||
def split(pattern, string, maxsplit=0, flags=0):
|
||||
return compile(pattern, flags).split(string, maxsplit)
|
||||
|
||||
|
||||
def sub(pattern, repl, string, count=0, flags=0):
|
||||
return compile(pattern, flags).sub(repl, string, count)
|
||||
|
||||
|
||||
def findall(pattern, string, flags=0):
|
||||
return compile(pattern, flags).findall(string)
|
||||
39
micropython/pymodule/signal.py
Normal file
39
micropython/pymodule/signal.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# This module provides partial functionality of the CPython "signal" module for
|
||||
# MicroPython.
|
||||
import _posix
|
||||
|
||||
|
||||
def signal(signalnum, handler):
|
||||
return _posix.signal(signalnum, handler)
|
||||
|
||||
|
||||
SIG_IGN = _posix.SIG_IGN
|
||||
SIG_DFL = _posix.SIG_DFL
|
||||
SIGABRT = _posix.SIGABRT
|
||||
SIGALRM = _posix.SIGALRM
|
||||
SIGBUS = _posix.SIGBUS
|
||||
SIGCHLD = _posix.SIGCHLD
|
||||
SIGCONT = _posix.SIGCONT
|
||||
SIGFPE = _posix.SIGFPE
|
||||
SIGHUP = _posix.SIGHUP
|
||||
SIGILL = _posix.SIGILL
|
||||
SIGINT = _posix.SIGINT
|
||||
SIGKILL = _posix.SIGKILL
|
||||
SIGPIPE = _posix.SIGPIPE
|
||||
SIGQUIT = _posix.SIGQUIT
|
||||
SIGSEGV = _posix.SIGSEGV
|
||||
SIGSTOP = _posix.SIGSTOP
|
||||
SIGTERM = _posix.SIGTERM
|
||||
SIGTSTP = _posix.SIGTSTP
|
||||
SIGTTIN = _posix.SIGTTIN
|
||||
SIGTTOU = _posix.SIGTTOU
|
||||
SIGUSR1 = _posix.SIGUSR1
|
||||
SIGUSR2 = _posix.SIGUSR2
|
||||
SIGPOLL = _posix.SIGPOLL
|
||||
SIGPROF = _posix.SIGPROF
|
||||
SIGSYS = _posix.SIGSYS
|
||||
SIGTRAP = _posix.SIGTRAP
|
||||
SIGURG = _posix.SIGURG
|
||||
SIGVTALRM = _posix.SIGVTALRM
|
||||
SIGXCPU = _posix.SIGXCPU
|
||||
SIGXFSZ = _posix.SIGXFSZ
|
||||
266
micropython/pymodule/socket.py
Normal file
266
micropython/pymodule/socket.py
Normal file
@@ -0,0 +1,266 @@
|
||||
# This module provides partial functionality of the CPython "socket" module for
|
||||
# MicroPython.
|
||||
|
||||
import sys as _sys
|
||||
_path = _sys.path
|
||||
_sys.path = ()
|
||||
try:
|
||||
import socket as _usocket
|
||||
finally:
|
||||
_sys.path = _path
|
||||
del _path
|
||||
|
||||
import _posix
|
||||
|
||||
|
||||
class TimeoutError(OSError):
|
||||
pass
|
||||
|
||||
|
||||
class gaierror(OSError):
|
||||
def __init__(self, *args):
|
||||
if len(args) == 1 and isinstance(args[0], int):
|
||||
errno = args[0]
|
||||
msg = "[Errno %d] %s" %(errno, _posix.gai_strerror(args[0]))
|
||||
super().__init__(msg)
|
||||
self.errno = errno
|
||||
else:
|
||||
super().__init__(*args)
|
||||
|
||||
|
||||
class socket(object):
|
||||
def __init__(self, family=_posix.AF_INET, type=_posix.SOCK_STREAM,
|
||||
proto=0, *, _sock=None):
|
||||
if _sock is not None:
|
||||
self._s = _sock
|
||||
else:
|
||||
self._s = _usocket.socket(family, type, proto)
|
||||
self.family = family
|
||||
self.type = type
|
||||
self.proto = proto
|
||||
self._closed = False
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
if not self._closed:
|
||||
self.close()
|
||||
|
||||
def _is_timeouterror(self, oserr):
|
||||
return oserr.errno in [_posix.ETIMEDOUT, _posix.EAGAIN]
|
||||
|
||||
def _arg_addr(self, addr):
|
||||
host, port = addr
|
||||
if host == '':
|
||||
if self.family == _posix.AF_INET:
|
||||
host = '0.0.0.0'
|
||||
elif self.family == _posix.AF_INET6:
|
||||
host = '::'
|
||||
if isinstance(port, int):
|
||||
port = str(port)
|
||||
return _getaddrinfo(
|
||||
host, port, self.family, self.type, self.proto,
|
||||
_posix.AI_NUMERICSERV
|
||||
)[0][4]
|
||||
|
||||
def _ret_addr(self, addr):
|
||||
host, serv = _getnameinfo(
|
||||
addr, _posix.NI_NUMERICHOST | _posix.NI_NUMERICSERV
|
||||
)
|
||||
return host, int(serv)
|
||||
|
||||
def fileno(self):
|
||||
if self._closed:
|
||||
return -1
|
||||
return self._s.fileno()
|
||||
|
||||
def bind(self, addr):
|
||||
addr = self._arg_addr(addr)
|
||||
self._s.bind(addr)
|
||||
|
||||
def listen(self, backlog):
|
||||
self._s.listen(backlog)
|
||||
|
||||
def accept(self):
|
||||
s, addr = self._s.accept()
|
||||
s = socket(self.family, self.type, self.proto, _sock=s)
|
||||
addr = self._ret_addr(addr)
|
||||
return s, addr
|
||||
|
||||
def connect(self, addr):
|
||||
addr = self._arg_addr(addr)
|
||||
try:
|
||||
self._s.connect(addr)
|
||||
except OSError as ex:
|
||||
if self._is_timeouterror(ex):
|
||||
raise timeout(ex) from None
|
||||
raise
|
||||
|
||||
def connect_ex(self, addr):
|
||||
try:
|
||||
self.connect(addr)
|
||||
except OSError as ex:
|
||||
return ex.errno
|
||||
else:
|
||||
return 0
|
||||
|
||||
def send(self, data):
|
||||
try:
|
||||
return self._s.send(data)
|
||||
except OSError as ex:
|
||||
if self._is_timeouterror(ex):
|
||||
raise timeout(ex) from None
|
||||
raise
|
||||
|
||||
def sendto(self, data, addr):
|
||||
addr = self._arg_addr(addr)
|
||||
try:
|
||||
return self._s.sendto(data, addr)
|
||||
except OSError as ex:
|
||||
if self._is_timeouterror(ex):
|
||||
raise timeout(ex) from None
|
||||
raise
|
||||
|
||||
def sendall(self, data):
|
||||
try:
|
||||
tosend = data
|
||||
while tosend:
|
||||
size = self.send(tosend)
|
||||
tosend = tosend[size:]
|
||||
except OSError as ex:
|
||||
if self._is_timeouterror(ex):
|
||||
raise timeout(ex) from None
|
||||
raise
|
||||
|
||||
def recv(self, bufsize):
|
||||
try:
|
||||
return self._s.recv(bufsize)
|
||||
except OSError as ex:
|
||||
if self._is_timeouterror(ex):
|
||||
raise timeout(ex) from None
|
||||
raise
|
||||
|
||||
def recvfrom(self, bufsize):
|
||||
try:
|
||||
data, addr = self._s.recvfrom(bufsize)
|
||||
except OSError as ex:
|
||||
if self._is_timeouterror(ex):
|
||||
raise timeout(ex) from None
|
||||
raise
|
||||
addr = self._ret_addr(addr)
|
||||
return data, addr
|
||||
|
||||
def shutdown(self, how):
|
||||
_posix.shutdown(self.fileno(), how)
|
||||
|
||||
def close(self):
|
||||
if not self._closed:
|
||||
self._s.close()
|
||||
self._closed = True
|
||||
|
||||
def getsockname(self):
|
||||
addr = _posix.getsockname(self.fileno())
|
||||
return self._ret_addr(addr)
|
||||
|
||||
def getpeername(self):
|
||||
addr = _posix.getpeername(self.fileno())
|
||||
return self._ret_addr(addr)
|
||||
|
||||
def setsockopt(self, level, optname, value):
|
||||
return self._s.setsockopt(level, optname, value)
|
||||
|
||||
def settimeout(self, value):
|
||||
return self._s.settimeout(value)
|
||||
|
||||
def setblocking(self, flag):
|
||||
return self._s.setblocking(flag)
|
||||
|
||||
|
||||
def inet_aton(ip_addr):
|
||||
return _usocket.inet_pton(_posix.AF_INET, ip_addr)
|
||||
|
||||
|
||||
def inet_ntoa(packed_ip):
|
||||
return _usocket.inet_ntop(_posix.AF_INET, packed_ip)
|
||||
|
||||
|
||||
def _getaddrinfo(*args, **kwargs):
|
||||
try:
|
||||
return _posix.getaddrinfo(*args, **kwargs)
|
||||
except OSError as ex:
|
||||
raise gaierror(ex.errno) from None
|
||||
|
||||
|
||||
def _getnameinfo(*args, **kwargs):
|
||||
try:
|
||||
return _posix.getnameinfo(*args, **kwargs)
|
||||
except OSError as ex:
|
||||
raise gaierror(ex.errno) from None
|
||||
|
||||
|
||||
error = OSError
|
||||
timeout = TimeoutError
|
||||
|
||||
inet_pton = _usocket.inet_pton
|
||||
inet_ntop = _usocket.inet_ntop
|
||||
|
||||
|
||||
SOCK_DGRAM = _posix.SOCK_DGRAM
|
||||
SOCK_RAW = _posix.SOCK_RAW
|
||||
SOCK_SEQPACKET = _posix.SOCK_SEQPACKET
|
||||
SOCK_STREAM = _posix.SOCK_STREAM
|
||||
SOL_SOCKET = _posix.SOL_SOCKET
|
||||
SO_ACCEPTCONN = _posix.SO_ACCEPTCONN
|
||||
if hasattr(_posix, 'SO_BINDTODEVICE'):
|
||||
SO_BINDTODEVICE = _posix.SO_BINDTODEVICE
|
||||
SO_BROADCAST = _posix.SO_BROADCAST
|
||||
SO_DEBUG = _posix.SO_DEBUG
|
||||
SO_DONTROUTE = _posix.SO_DONTROUTE
|
||||
SO_ERROR = _posix.SO_ERROR
|
||||
SO_KEEPALIVE = _posix.SO_KEEPALIVE
|
||||
SO_LINGER = _posix.SO_LINGER
|
||||
SO_OOBINLINE = _posix.SO_OOBINLINE
|
||||
SO_RCVBUF = _posix.SO_RCVBUF
|
||||
SO_RCVLOWAT = _posix.SO_RCVLOWAT
|
||||
SO_RCVTIMEO = _posix.SO_RCVTIMEO
|
||||
SO_REUSEADDR = _posix.SO_REUSEADDR
|
||||
if hasattr(_posix, 'SO_REUSEPORT'):
|
||||
SO_REUSEPORT = _posix.SO_REUSEPORT
|
||||
SO_SNDBUF = _posix.SO_SNDBUF
|
||||
SO_SNDLOWAT = _posix.SO_SNDLOWAT
|
||||
SO_SNDTIMEO = _posix.SO_SNDTIMEO
|
||||
SO_TYPE = _posix.SO_TYPE
|
||||
SOMAXCONN = _posix.SOMAXCONN
|
||||
MSG_CTRUNC = _posix.MSG_CTRUNC
|
||||
MSG_DONTROUTE = _posix.MSG_DONTROUTE
|
||||
MSG_EOR = _posix.MSG_EOR
|
||||
MSG_OOB = _posix.MSG_OOB
|
||||
MSG_PEEK = _posix.MSG_PEEK
|
||||
MSG_TRUNC = _posix.MSG_TRUNC
|
||||
MSG_WAITALL = _posix.MSG_WAITALL
|
||||
AF_INET = _posix.AF_INET
|
||||
AF_INET6 = _posix.AF_INET6
|
||||
AF_UNIX = _posix.AF_UNIX
|
||||
AF_UNSPEC = _posix.AF_UNSPEC
|
||||
SHUT_RD = _posix.SHUT_RD
|
||||
SHUT_RDWR = _posix.SHUT_RDWR
|
||||
SHUT_WR = _posix.SHUT_WR
|
||||
IPPROTO_IP = _posix.IPPROTO_IP
|
||||
IPPROTO_IPV6 = _posix.IPPROTO_IPV6
|
||||
IPPROTO_ICMP = _posix.IPPROTO_ICMP
|
||||
IPPROTO_RAW = _posix.IPPROTO_RAW
|
||||
IPPROTO_TCP = _posix.IPPROTO_TCP
|
||||
IPPROTO_UDP = _posix.IPPROTO_UDP
|
||||
INADDR_ANY = _posix.INADDR_ANY
|
||||
INADDR_BROADCAST = _posix.INADDR_BROADCAST
|
||||
INET_ADDRSTRLEN = _posix.INET_ADDRSTRLEN
|
||||
INET6_ADDRSTRLEN = _posix.INET6_ADDRSTRLEN
|
||||
IPV6_JOIN_GROUP = _posix.IPV6_JOIN_GROUP
|
||||
IPV6_LEAVE_GROUP = _posix.IPV6_LEAVE_GROUP
|
||||
IPV6_MULTICAST_HOPS = _posix.IPV6_MULTICAST_HOPS
|
||||
IPV6_MULTICAST_IF = _posix.IPV6_MULTICAST_IF
|
||||
IPV6_MULTICAST_LOOP = _posix.IPV6_MULTICAST_LOOP
|
||||
IPV6_UNICAST_HOPS = _posix.IPV6_UNICAST_HOPS
|
||||
IPV6_V6ONLY = _posix.IPV6_V6ONLY
|
||||
TCP_NODELAY = _posix.TCP_NODELAY
|
||||
57
micropython/pymodule/struct.py
Normal file
57
micropython/pymodule/struct.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# This module provides partial functionality of the CPython "struct" module for
|
||||
# MicroPython.
|
||||
|
||||
import sys as _sys
|
||||
_path = _sys.path
|
||||
_sys.path = ()
|
||||
try:
|
||||
import struct as _ustruct
|
||||
finally:
|
||||
_sys.path = _path
|
||||
del _path
|
||||
|
||||
__all__ = [
|
||||
'calcsize', 'pack', 'pack_into', 'unpack', 'unpack_from'
|
||||
]
|
||||
|
||||
|
||||
class _StructError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
error = _StructError
|
||||
|
||||
|
||||
def pack(format, *args):
|
||||
try:
|
||||
return _ustruct.pack(format, *args)
|
||||
except Exception as ex:
|
||||
raise error(ex) from None
|
||||
|
||||
|
||||
def unpack(format, buffer):
|
||||
try:
|
||||
return _ustruct.unpack(format, buffer)
|
||||
except Exception as ex:
|
||||
raise error(ex) from None
|
||||
|
||||
|
||||
def pack_into(format, buffer, offset, *args):
|
||||
try:
|
||||
return _ustruct.pack_into(format, buffer, offset, *args)
|
||||
except Exception as ex:
|
||||
raise error(ex) from None
|
||||
|
||||
|
||||
def unpack_from(format, buffer, offset=0):
|
||||
try:
|
||||
return _ustruct.unpack_from(format, buffer, offset)
|
||||
except Exception as ex:
|
||||
raise error(ex) from None
|
||||
|
||||
|
||||
def calcsize(format):
|
||||
try:
|
||||
return _ustruct.calcsize(format)
|
||||
except Exception as ex:
|
||||
raise error(ex) from None
|
||||
254
micropython/pymodule/subprocess.py
Normal file
254
micropython/pymodule/subprocess.py
Normal file
@@ -0,0 +1,254 @@
|
||||
# This module provides partial functionality of the CPython "subprocess" module
|
||||
# for MicroPython.
|
||||
# Note: Thread safety is not guaranteed.
|
||||
|
||||
import sys as _usys
|
||||
import _posix
|
||||
|
||||
__all__ = [
|
||||
'CalledProcessError', 'Popen', 'STDOUT', 'SubprocessError', 'check_output'
|
||||
]
|
||||
|
||||
|
||||
STDOUT = -2
|
||||
|
||||
|
||||
class SubprocessError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CalledProcessError(SubprocessError):
|
||||
def __init__(self, returncode, cmd, output=None):
|
||||
self.returncode = returncode
|
||||
self.cmd = cmd
|
||||
self.output = output
|
||||
|
||||
def __str__(self):
|
||||
return "Command '%s' returned non-zero exit status %d" % (
|
||||
self.cmd, self.returncode
|
||||
)
|
||||
|
||||
|
||||
def _handle_exitstatus(sts):
|
||||
if _posix.WIFSIGNALED(sts):
|
||||
return -(_posix.WTERMSIG(sts))
|
||||
elif _posix.WIFEXITED(sts):
|
||||
return _posix.WEXITSTATUS(sts)
|
||||
else:
|
||||
# Should never happen
|
||||
raise SubprocessError("Unknown child exit status!")
|
||||
|
||||
|
||||
def _close_fd(fd):
|
||||
if fd < 0:
|
||||
return
|
||||
try:
|
||||
_posix.close(fd)
|
||||
fd = -1
|
||||
except OSError as ex:
|
||||
_usys.stderr.write('close(): %s\n' % str(ex))
|
||||
return fd
|
||||
|
||||
|
||||
def _kill_child(pid, signal):
|
||||
if pid <= 0:
|
||||
return
|
||||
_, sts = _posix.waitpid(pid, _posix.WNOHANG)
|
||||
if not sts:
|
||||
try:
|
||||
_posix.kill(pid, signal)
|
||||
except OSError as ex:
|
||||
if ex.errno != _posix.ESRCH:
|
||||
raise
|
||||
_posix.waitpid(pid, 0)
|
||||
|
||||
|
||||
def _set_fd_cloexec(fd):
|
||||
flags = _posix.fcntl(fd, _posix.F_GETFD, None)
|
||||
_posix.fcntl(fd, _posix.F_SETFD, flags | _posix.FD_CLOEXEC)
|
||||
|
||||
|
||||
def check_output(args, *, stderr=None):
|
||||
if stderr is not None and stderr != STDOUT:
|
||||
raise NotImplementedError("Unsupported stderr redirection")
|
||||
|
||||
executable = args[0]
|
||||
r, w = _posix.pipe()
|
||||
er, ew = _posix.pipe()
|
||||
_set_fd_cloexec(er)
|
||||
_set_fd_cloexec(ew)
|
||||
|
||||
try:
|
||||
pid = _posix.fork()
|
||||
except Exception:
|
||||
_close_fd(r)
|
||||
_close_fd(w)
|
||||
raise
|
||||
|
||||
if pid == 0:
|
||||
# child
|
||||
try:
|
||||
r = _close_fd(r)
|
||||
er = _close_fd(er)
|
||||
_posix.dup2(w, _posix.STDOUT_FILENO)
|
||||
if stderr == STDOUT:
|
||||
_posix.dup2(w, _posix.STDERR_FILENO)
|
||||
w = _close_fd(w)
|
||||
_posix.execvp(executable, args)
|
||||
except OSError as ex:
|
||||
_posix.write(ew, str(ex.errno).encode())
|
||||
finally:
|
||||
_close_fd(r)
|
||||
_close_fd(er)
|
||||
_close_fd(w)
|
||||
_close_fd(ew)
|
||||
_posix._exit(1)
|
||||
else:
|
||||
# parent
|
||||
try:
|
||||
w = _close_fd(w)
|
||||
ew = _close_fd(ew)
|
||||
|
||||
output_l = []
|
||||
while True:
|
||||
chunk = _posix.read(r, _posix.BUFSIZ)
|
||||
if not chunk:
|
||||
break
|
||||
output_l.append(chunk)
|
||||
|
||||
errno_l = []
|
||||
while True:
|
||||
chunk = _posix.read(er, _posix.BUFSIZ)
|
||||
if not chunk:
|
||||
break
|
||||
errno_l.append(chunk)
|
||||
|
||||
r = _close_fd(r)
|
||||
er = _close_fd(er)
|
||||
|
||||
output = b''.join(output_l)
|
||||
errno_b = b''.join(errno_l)
|
||||
|
||||
_, status = _posix.waitpid(pid, 0)
|
||||
pid = -1
|
||||
|
||||
if errno_b:
|
||||
errno = int(errno_b.decode())
|
||||
raise OSError(errno)
|
||||
|
||||
retcode = _handle_exitstatus(status)
|
||||
if retcode:
|
||||
raise CalledProcessError(retcode, args, output)
|
||||
return output
|
||||
finally:
|
||||
_close_fd(r)
|
||||
_close_fd(er)
|
||||
_close_fd(w)
|
||||
_close_fd(ew)
|
||||
_kill_child(pid, _posix.SIGKILL)
|
||||
|
||||
|
||||
class Popen(object):
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
self.pid = None
|
||||
self.returncode = None
|
||||
self._start_child()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.wait()
|
||||
|
||||
def _start_child(self):
|
||||
executable = self.args[0]
|
||||
|
||||
er, ew = _posix.pipe()
|
||||
_set_fd_cloexec(er)
|
||||
_set_fd_cloexec(ew)
|
||||
|
||||
try:
|
||||
pid = _posix.fork()
|
||||
except Exception:
|
||||
_close_fd(er)
|
||||
_close_fd(ew)
|
||||
raise
|
||||
|
||||
if pid == 0:
|
||||
# child
|
||||
try:
|
||||
er = _close_fd(er)
|
||||
_posix.execvp(executable, self.args)
|
||||
except OSError as ex:
|
||||
_posix.write(ew, str(ex.errno).encode())
|
||||
finally:
|
||||
_close_fd(er)
|
||||
_close_fd(ew)
|
||||
_posix._exit(1)
|
||||
else:
|
||||
# parent
|
||||
self.pid = pid
|
||||
try:
|
||||
ew = _close_fd(ew)
|
||||
|
||||
errno_l = []
|
||||
while True:
|
||||
chunk = _posix.read(er, _posix.BUFSIZ)
|
||||
if not chunk:
|
||||
break
|
||||
errno_l.append(chunk)
|
||||
|
||||
er = _close_fd(er)
|
||||
|
||||
errno_b = b''.join(errno_l)
|
||||
if errno_b:
|
||||
errno = int(errno_b.decode())
|
||||
raise OSError(errno)
|
||||
except Exception:
|
||||
_kill_child(pid, _posix.SIGKILL)
|
||||
raise
|
||||
|
||||
finally:
|
||||
_close_fd(er)
|
||||
_close_fd(ew)
|
||||
|
||||
def poll(self):
|
||||
if self.returncode is not None:
|
||||
return self.returncode
|
||||
try:
|
||||
pid, sts = _posix.waitpid(self.pid, _posix.WNOHANG)
|
||||
if pid == self.pid:
|
||||
self.returncode = _handle_exitstatus(sts)
|
||||
except OSError as e:
|
||||
if e.errno == _posix.ECHILD:
|
||||
self.returncode = 0
|
||||
return self.returncode
|
||||
|
||||
def wait(self):
|
||||
if self.returncode is not None:
|
||||
return self.returncode
|
||||
try:
|
||||
_, sts = _posix.waitpid(self.pid, 0)
|
||||
self.returncode = _handle_exitstatus(sts)
|
||||
except OSError as ex:
|
||||
if ex.errno != _posix.ECHILD:
|
||||
raise
|
||||
self.returncode = 0
|
||||
return self.returncode
|
||||
|
||||
def send_signal(self, sig):
|
||||
self.poll()
|
||||
if self.returncode is not None:
|
||||
return
|
||||
try:
|
||||
_posix.kill(self.pid, sig)
|
||||
except OSError as ex:
|
||||
if ex.errno != _posix.ESRCH:
|
||||
raise
|
||||
|
||||
def terminate(self):
|
||||
self.send_signal(_posix.SIGTERM)
|
||||
|
||||
def kill(self):
|
||||
self.send_signal(_posix.SIGKILL)
|
||||
106
micropython/pymodule/threading.py
Normal file
106
micropython/pymodule/threading.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# This module provides partial functionality of the CPython "threading" module
|
||||
# for MicroPython.
|
||||
|
||||
import _thread
|
||||
|
||||
__all__ = [
|
||||
'Thread', 'active_count', 'current_thread', 'main_thread'
|
||||
]
|
||||
|
||||
|
||||
class Thread(object):
|
||||
_lock = _thread.allocate_lock()
|
||||
_active = dict()
|
||||
|
||||
def __init__(self, group=None, target=None, name=None, args=(),
|
||||
kwargs=None):
|
||||
if group is not None:
|
||||
raise NotImplementedError("group argument must be None for now")
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
self.name = str(name or "unnamed thread")
|
||||
self.ident = None
|
||||
self._target = target
|
||||
self._args = args
|
||||
self._kwargs = kwargs
|
||||
self._start_called = False
|
||||
self._is_started = False
|
||||
self._is_stopped = False
|
||||
self._initialized = True
|
||||
self._join_lck = _thread.allocate_lock()
|
||||
|
||||
def _pre_run(self):
|
||||
# this method is internally called inside the child thread
|
||||
self._join_lck.acquire()
|
||||
self.ident = _thread.get_ident()
|
||||
Thread._lock.acquire()
|
||||
Thread._active[self.ident] = self
|
||||
Thread._lock.release()
|
||||
self._is_started = True
|
||||
|
||||
def _post_run(self):
|
||||
# this method is internally called inside the child thread
|
||||
self._is_stopped = True
|
||||
Thread._lock.acquire()
|
||||
del Thread._active[self.ident]
|
||||
Thread._lock.release()
|
||||
self._join_lck.release()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if self._target:
|
||||
self._target(*self._args, **self._kwargs)
|
||||
finally:
|
||||
del self._target, self._args, self._kwargs
|
||||
|
||||
def start(self):
|
||||
if not self._initialized:
|
||||
raise RuntimeError("thread.__init__() not called")
|
||||
if self._start_called:
|
||||
raise RuntimeError("threads can only be started once")
|
||||
def _entry():
|
||||
self._pre_run()
|
||||
try:
|
||||
self.run()
|
||||
finally:
|
||||
self._post_run()
|
||||
self._start_called = True
|
||||
_thread.start_new_thread(_entry, ())
|
||||
|
||||
def is_alive(self):
|
||||
if not self._initialized:
|
||||
raise RuntimeError("thread.__init__() not called")
|
||||
return self._is_started and not self._is_stopped
|
||||
|
||||
def join(self):
|
||||
if not self._initialized:
|
||||
raise RuntimeError("thread.__init__() not called")
|
||||
if not self._is_started:
|
||||
raise RuntimeError("cannot join thread before it is started")
|
||||
if self.ident == _thread.get_ident():
|
||||
raise RuntimeError("cannot join current thread")
|
||||
self._join_lck.acquire()
|
||||
self._join_lck.release()
|
||||
|
||||
|
||||
class _MainThread(Thread):
|
||||
def __init__(self):
|
||||
super().__init__(name="MainThread")
|
||||
self._start_called = True
|
||||
self._pre_run()
|
||||
|
||||
|
||||
_main_thread = _MainThread()
|
||||
|
||||
|
||||
def active_count():
|
||||
return len(Thread._active)
|
||||
|
||||
|
||||
def current_thread():
|
||||
ident = _thread.get_ident()
|
||||
return Thread._active[ident]
|
||||
|
||||
|
||||
def main_thread():
|
||||
return _main_thread
|
||||
Reference in New Issue
Block a user