Merge pull request #395 from awachtler/master

added JSON Topic for use with micropython-upip
This commit is contained in:
Dmitrii Orlov 2021-08-26 13:39:32 +02:00 committed by GitHub
commit 3713da9d66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 0 deletions

View File

@ -884,6 +884,32 @@ these steps:
you may add the user under which ``pypiserver`` runs into the *shadow*
group, with a command like this: ``sudo usermod -a -G shadow pypy-user``.
Use with MicroPython
--------------------
The MicroPython interpreter for embedded devices can install packages with the
module ``upip.py``. The module uses a specialized json-endpoint to retrieve
package information. This endpoint is supported by ``pypiserver``.
It can be tested with the UNIX port of ``micropython``::
cd micropython
ports/unix/micropython -m tools.upip install -i http://my-server:8080 -p /tmp/mymodules micropython-foobar
Installing packages from the REPL of an embedded device works in this way:
.. code-block:: python
import network
import upip
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('<your ESSID>', '<your password>')
upip.index_urls = ["http://my-server:8080"]
upip.install("micropython-foobar")
Further information on micropython-packaging can be found here: https://docs.micropython.org/en/latest/reference/packages.html
Sources
=======

View File

@ -8,6 +8,7 @@ import zipfile
from collections import namedtuple
from io import BytesIO
from urllib.parse import urljoin, urlparse
from json import dumps
from pypiserver.config import RunConfig
from . import __version__
@ -362,6 +363,34 @@ def server_static(filename):
return HTTPError(404, f"Not Found ({filename} does not exist)\n\n")
@app.route("/:project/json")
@auth("list")
def json_info(project):
# PEP 503: require normalized project
normalized = normalize_pkgname_for_url(project)
if project != normalized:
return redirect(f"/{normalized}/json", 301)
packages = sorted(
config.backend.find_project_packages(project),
key=lambda x: x.parsed_version, reverse=True
)
if not packages:
raise HTTPError(404, f"package {project} not found")
latest_version = packages[0].version
releases = {}
req_url = request.url
for x in packages:
releases[x.version] = [{"url": urljoin(req_url, "../../packages/" + x.relfn)}]
rv = {
"info" : {"version": latest_version},
"releases" : releases
}
response.content_type = 'application/json'
return dumps(rv)
@app.route("/:project")
@app.route("/:project/")

View File

@ -419,6 +419,39 @@ def test_simple_index_list_name_with_underscore_no_egg(root, testapp):
assert hrefs == {"foo-bar/"}
def test_json_info(root, testapp):
root.join("foobar-1.0.zip").write("")
root.join("foobar-1.1.zip").write("")
root.join("foobarX-1.1.zip").write("")
resp = testapp.get("/foobar/json")
assert "info" in resp.json
assert "releases" in resp.json
assert len(resp.json["info"]) == 1
assert len(resp.json["releases"]) == 2
def test_json_info_package_not_existing(root, testapp):
resp = testapp.get("/foobar/json", status=404)
@pytest.mark.parametrize(
"package,normalized",
[
("FooBar", "foobar"),
("Foo.Bar", "foo-bar"),
("foo_bar", "foo-bar"),
("Foo-Bar", "foo-bar"),
("foo--_.bar", "foo-bar"),
],
)
def test_json_info_normalized_name_redirect(testapp, package, normalized):
resp = testapp.get("/{0}/json".format(package))
assert resp.status_code >= 300
assert resp.status_code < 400
assert resp.location.endswith("/{0}/json".format(normalized))
def test_no_cache_control_set(root, testapp):
assert not testapp.app._pypiserver_config.cache_control
root.join("foo_bar-1.0.tar.gz").write("")