-
Notifications
You must be signed in to change notification settings - Fork 26
Make upip installable #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# This module is part of Pycopy https://github.com/pfalcon/pycopy | ||
# and pycopy-lib https://github.com/pfalcon/pycopy-lib, projects to | ||
# create a (very) lightweight full-stack Python distribution. | ||
# | ||
# Copyright (c) 2016-2019 Paul Sokolovsky | ||
# Licence: MIT | ||
# | ||
# This module overrides distutils (also compatible with setuptools) "sdist" | ||
# command to perform pre- and post-processing as required for Pycopy's | ||
# upip package manager. | ||
# | ||
# Preprocessing steps: | ||
# * Creation of Python resource module (R.py) from each top-level package's | ||
# resources. | ||
# Postprocessing steps: | ||
# * Removing metadata files not used by upip (this includes setup.py) | ||
# * Recompressing gzip archive with 4K dictionary size so it can be | ||
# installed even on low-heap targets. | ||
# | ||
import sys | ||
import os | ||
import zlib | ||
from subprocess import Popen, PIPE | ||
import glob | ||
import tarfile | ||
import re | ||
import io | ||
|
||
from distutils.filelist import FileList | ||
from setuptools.command.sdist import sdist as _sdist | ||
|
||
|
||
def gzip_4k(inf, fname): | ||
comp = zlib.compressobj(level=9, wbits=16 + 12) | ||
with open(fname + ".out", "wb") as outf: | ||
while 1: | ||
data = inf.read(1024) | ||
if not data: | ||
break | ||
outf.write(comp.compress(data)) | ||
outf.write(comp.flush()) | ||
os.rename(fname, fname + ".orig") | ||
os.rename(fname + ".out", fname) | ||
|
||
|
||
FILTERS = [ | ||
# include, exclude, repeat | ||
(r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"), | ||
(r".+\.py$", r"[^/]+$"), | ||
(None, r".+\.egg-info/.+"), | ||
] | ||
|
||
|
||
outbuf = io.BytesIO() | ||
|
||
def filter_tar(name): | ||
fin = tarfile.open(name, "r:gz") | ||
fout = tarfile.open(fileobj=outbuf, mode="w") | ||
for info in fin: | ||
# print(info) | ||
if not "/" in info.name: | ||
continue | ||
fname = info.name.split("/", 1)[1] | ||
include = None | ||
|
||
for inc_re, exc_re in FILTERS: | ||
if include is None and inc_re: | ||
if re.match(inc_re, fname): | ||
include = True | ||
|
||
if include is None and exc_re: | ||
if re.match(exc_re, fname): | ||
include = False | ||
|
||
if include is None: | ||
include = True | ||
|
||
if include: | ||
print("including:", fname) | ||
else: | ||
print("excluding:", fname) | ||
continue | ||
|
||
farch = fin.extractfile(info) | ||
fout.addfile(info, farch) | ||
fout.close() | ||
fin.close() | ||
|
||
|
||
def make_resource_module(manifest_files): | ||
resources = [] | ||
# Any non-python file included in manifest is resource | ||
for fname in manifest_files: | ||
ext = fname.rsplit(".", 1) | ||
if len(ext) > 1: | ||
ext = ext[1] | ||
else: | ||
ext = "" | ||
if ext != "py": | ||
resources.append(fname) | ||
|
||
if resources: | ||
print("creating resource module R.py") | ||
resources.sort() | ||
last_pkg = None | ||
r_file = None | ||
for fname in resources: | ||
try: | ||
pkg, res_name = fname.split("/", 1) | ||
except ValueError: | ||
print("not treating %s as a resource" % fname) | ||
continue | ||
if last_pkg != pkg: | ||
last_pkg = pkg | ||
if r_file: | ||
r_file.write("}\n") | ||
r_file.close() | ||
r_file = open(pkg + "/R.py", "w") | ||
r_file.write("R = {\n") | ||
|
||
with open(fname, "rb") as f: | ||
r_file.write("%r: %r,\n" % (res_name, f.read())) | ||
|
||
if r_file: | ||
r_file.write("}\n") | ||
r_file.close() | ||
|
||
|
||
class sdist(_sdist): | ||
|
||
def run(self): | ||
self.filelist = FileList() | ||
self.get_file_list() | ||
make_resource_module(self.filelist.files) | ||
|
||
r = super().run() | ||
|
||
assert len(self.archive_files) == 1 | ||
print("filtering files and recompressing with 4K dictionary") | ||
filter_tar(self.archive_files[0]) | ||
outbuf.seek(0) | ||
gzip_4k(outbuf, self.archive_files[0]) | ||
|
||
return r | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. code quality here could be better. unclear: is this the usual code used for this purpose / is there anything better? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also: do we need to bundle this or can we just pip install something to get this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used the file as-is. Other than the comments at the topic referring to "pycopy-lib" the file is essentially the same as the file which was part of "micropython-lib". I would keep the file "as-is" (including to allow comparing it to the source in the future, if the source might have changed/improved). About bundling: I searched hard to find an installable version of this. I didnt manage. I did find a number of micropython modules (e.g. micropython-umqtt.simple2) that do have a setup.py, which import sdist_upip, but that don't ship along that file. So there could be a way yet to install that file in a way I couldn't figure out. I did find one module that shipped the file along. Interestingly micropython-umqtt.simple2 imports sdist_upip from the parent directory So to summarise: I could not find a place to pip install it from and others seem to also rely on the file from either micropython-lib or pycopy-lib, so I chose the bundling option. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. I agree to use 3rd party code "as is" to simplify updates (if any). If there is no alternative, this is as good as it gets. |
||
|
||
# For testing only | ||
if __name__ == "__main__": | ||
filter_tar(sys.argv[1]) | ||
outbuf.seek(0) | ||
gzip_4k(outbuf, sys.argv[1]) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from pathlib import Path | ||
from setuptools import setup | ||
import sdist_upip | ||
|
||
|
||
HERE = Path(__file__).parent | ||
README = (HERE / 'README.rst').read_text() | ||
|
||
VERSION = "1.0.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. over time, we'll need to improve how this is handled. either by using a tool that updates versions everywhere (here, code, docs, ...) or by deriving version from git (for other "normal python" projects i use setuptools_scm). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saying, it's ok to have it hard coded for now, and only improve later? (It might be good to not take on too much more before getting to v1.0.0) But I like the approach of deriving the version from git. Especially when putting the build/publish into a Github Action, it would allow understanding where each build artifact actually came from. Also, given that this setup.py is run with python3 (the dependencies alone make it not run on MicroPython), I would expect setuptools_scm to work just fine (i.e. that there's nothing MicroPython specific here). Let me know if you feel this should be addressed before launch of v1.0.0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok for now. not sure if setuptools_scm can be used, it is made for normal python code in a git repo. |
||
|
||
setup( | ||
name="micropython-py-esp32-ulp", | ||
version=VERSION, | ||
description="Assembler toolchain for the ESP32 ULP co-processor, written in MicroPython", | ||
long_description=README, | ||
long_description_content_type='text/x-rst', | ||
url="https://github.com/ThomasWaldmann/py-esp32-ulp", | ||
license="MIT", | ||
author="py-esp32-ulp authors", | ||
author_email="tw@waldmann-edv.de", | ||
maintainer="py-esp32-ulp authors", | ||
maintainer_email="tw@waldmann-edv.de", | ||
classifiers=[ | ||
'License :: OSI Approved :: MIT License', | ||
'Programming Language :: Python :: Implementation :: MicroPython', | ||
], | ||
platforms=["esp32"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, guess we also have linux/unix here. just leave it away? not sure what the valid values here are. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added "linux" and "darwin". (pushed as extra commit on top) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as long as it is valid and not rejected by pypi, we can keep it. |
||
cmdclass={"sdist": sdist_upip.sdist}, | ||
packages=["esp32_ulp"], | ||
) |
Uh oh!
There was an error while loading. Please reload this page.