From efc3625de6d54a82b54725be409486919cefdfdb Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 6 Aug 2025 14:50:21 -0400 Subject: [PATCH 1/3] Fix CI update converter notebooks to not write to home directory --- .github/workflows/ci.yml | 4 +- notebooks/Your_first_ASDF_converter.ipynb | 217 +----- .../Your_first_ASDF_converter/pyproject.toml | 18 + .../src/mfconverter/__init__.py | 0 .../src/mfconverter/converter.py | 24 + .../src/mfconverter/extensions.py | 11 + .../src/mfconverter/photo_id.py | 11 + notebooks/Your_second_ASDF_converter.ipynb | 671 +----------------- .../Your_second_ASDF_converter/pyproject.toml | 18 + .../src/myconverters/__init__.py | 0 .../src/myconverters/converters.py | 46 ++ .../src/myconverters/extensions.py | 15 + .../src/myconverters/integration.py | 3 + .../src/myconverters/photo_id.py | 11 + .../src/myconverters/traffic_citation.py | 12 + .../src/myschemas/__init__.py | 0 .../src/myschemas/integration.py | 26 + .../src/myschemas/resources/__init__.py | 0 .../resources/manifests/allmyschemas-1.0.yaml | 23 + .../resources/schemas/photo_id-1.0.0.yaml | 24 + .../schemas/traffic_citation-1.0.0.yaml | 29 + tox.ini | 2 - 22 files changed, 279 insertions(+), 886 deletions(-) create mode 100644 notebooks/Your_first_ASDF_converter/pyproject.toml create mode 100644 notebooks/Your_first_ASDF_converter/src/mfconverter/__init__.py create mode 100644 notebooks/Your_first_ASDF_converter/src/mfconverter/converter.py create mode 100644 notebooks/Your_first_ASDF_converter/src/mfconverter/extensions.py create mode 100644 notebooks/Your_first_ASDF_converter/src/mfconverter/photo_id.py create mode 100644 notebooks/Your_second_ASDF_converter/pyproject.toml create mode 100644 notebooks/Your_second_ASDF_converter/src/myconverters/__init__.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myconverters/converters.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myconverters/extensions.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myconverters/integration.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myconverters/photo_id.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myconverters/traffic_citation.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myschemas/__init__.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myschemas/integration.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myschemas/resources/__init__.py create mode 100644 notebooks/Your_second_ASDF_converter/src/myschemas/resources/manifests/allmyschemas-1.0.yaml create mode 100644 notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/photo_id-1.0.0.yaml create mode 100644 notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/traffic_citation-1.0.0.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4515ae..32e8f31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,8 @@ on: branches: - main pull_request: - types: - - synchronize + branches: + - main # Only cancel in-progress jobs or runs for the current workflow diff --git a/notebooks/Your_first_ASDF_converter.ipynb b/notebooks/Your_first_ASDF_converter.ipynb index dfdf935..4a01dbc 100644 --- a/notebooks/Your_first_ASDF_converter.ipynb +++ b/notebooks/Your_first_ASDF_converter.ipynb @@ -102,79 +102,6 @@ "leave it be." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "5fec10da", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir ~/converter_tutorial" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3b1e163f", - "metadata": {}, - "outputs": [], - "source": [ - "cd ~/converter_tutorial" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "06a42933", - "metadata": {}, - "outputs": [], - "source": [ - "# Record current directory for restarts\n", - "import os\n", - "curdir = os.getcwd()\n", - "print(curdir)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0ae4a184", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir mfconverter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "46d22a46", - "metadata": {}, - "outputs": [], - "source": [ - "cd mfconverter" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a980c3f9", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8dbb76d3", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src/mfconverter" - ] - }, { "cell_type": "markdown", "id": "ede348bd", @@ -183,38 +110,6 @@ "And now we will create a module that has a very, very simple photo ID class and add a package `__init__.py`" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "f045f111", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/mfconverter/photo_id.py\n", - "class PhotoID:\n", - " \"Holds Photo ID information\"\n", - "\n", - " def __init__(self, last_name, first_name, photo):\n", - " \"expects a monochromatic numpy array for photo\"\n", - " self.last_name = last_name\n", - " self.first_name = first_name\n", - " self.photo = photo\n", - " \n", - " def name(self):\n", - " return self.last_name + ', ' + self.first_name" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ad205d2e", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/__init__.py\n", - "\n" - ] - }, { "cell_type": "markdown", "id": "09ee1385", @@ -223,40 +118,6 @@ "Next we create the file that contains the converter code" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "aa345e79", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/mfconverter/converter.py\n", - "from asdf.extension import Converter\n", - "\n", - "class PhotoIDConverter(Converter):\n", - " tags = [\"asdf://stsci.edu/example-project/tags/photo_id-*\"]\n", - " types = [\"mfconverter.photo_id.PhotoID\"]\n", - " # The above registers the tag that the converter is used for, as well as\n", - " # associating the class that the converter is used for.\n", - " \n", - " # This method converts from the Python object to yaml\n", - " def to_yaml_tree(self, obj, tags, ctx):\n", - " # The yaml conversion expects a dictionary returned\n", - " node = {}\n", - " node['first_name'] = obj.first_name\n", - " node['last_name'] = obj.last_name\n", - " node['photo'] = obj.photo\n", - " return node\n", - " \n", - " # This method converts from yaml to the Python object\n", - " def from_yaml_tree(self, node, tag, ctx):\n", - " from .photo_id import PhotoID # Deferred import to avoid always importing \n", - " # when ASDF gets entry points.\n", - " return PhotoID(node['last_name'],\n", - " node['first_name'],\n", - " node['photo'])" - ] - }, { "cell_type": "markdown", "id": "55ca30cd", @@ -278,27 +139,6 @@ "We need to create a module for the entry point handling" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "f9c03910", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/mfconverter/extensions.py\n", - "from asdf.extension import Extension\n", - "from .converter import PhotoIDConverter\n", - "\n", - "class MFExtension(Extension):\n", - " extension_uri = \"asdf://stsci.edu/example-project/photo_id-1.0.0\"\n", - " tags = [\"asdf://stsci.edu/example-project/tags/photo_id-1.0.0\"]\n", - " converters = [PhotoIDConverter()]\n", - "\n", - "# The following will be called by ASDF when looking for ASDF entry points \n", - "def get_extensions():\n", - " return [MFExtension()]" - ] - }, { "cell_type": "markdown", "id": "412c3e4f", @@ -307,37 +147,6 @@ "And finally, the entry point reference in setup.cfg, provided here as a whole file." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "feb206d7", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile pyproject.toml\n", - "[project]\n", - "name = \"mfconverter\"\n", - "description = \"TODO\"\n", - "version='0.1.0'\n", - "requires-python = \">=3.9\"\n", - "dependencies = [\n", - " \"jsonschema >=3.0.2\",\n", - " \"asdf >=2.8\",\n", - " \"psutil >=5.7.2\",\n", - " \"numpy>=1.16\",\n", - "]\n", - "\n", - "[build-system]\n", - "requires = [\"setuptools >=61\", \"setuptools_scm[toml] >=3.4\"]\n", - "build-backend = \"setuptools.build_meta\"\n", - "\n", - "[project.entry-points.\"asdf.extensions\"]\n", - "mfconverter = \"mfconverter.extensions:get_extensions\"\n", - "\n", - "[tool.setuptools.packages.find]\n", - "where = [\"src\"]" - ] - }, { "cell_type": "markdown", "id": "8d0e3882", @@ -349,33 +158,13 @@ "We need the setup.py file too" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "3ffb22d6", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile setup.py\n", - "#!/usr/bin/env python3\n", - "from setuptools import setup\n", - "\n", - "setup()" - ] - }, { "cell_type": "markdown", "id": "b7628aaa", "metadata": {}, "source": [ "Install package\n", - "------------------\n", - "\n", - "This is best done from a terminal window using the command\n", - "\n", - "`pip install --editable .`\n", - "\n", - "But this notebook will do that, but a consequence is that if the reinstallation must be done, the Jupyter kernel must be restarted to pick up the new installation." + "------------------" ] }, { @@ -385,7 +174,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install --editable ." + "!pip install ./Your_first_ASDF_converter" ] }, { @@ -539,7 +328,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.10" + "version": "3.13.4" } }, "nbformat": 4, diff --git a/notebooks/Your_first_ASDF_converter/pyproject.toml b/notebooks/Your_first_ASDF_converter/pyproject.toml new file mode 100644 index 0000000..53d2aec --- /dev/null +++ b/notebooks/Your_first_ASDF_converter/pyproject.toml @@ -0,0 +1,18 @@ +[project] +name = "mfconverter" +description = "TODO" +version='0.1.0' +requires-python = ">=3.9" +dependencies = [ + "asdf >=2.8", +] + +[build-system] +requires = ["setuptools >=61", "setuptools_scm[toml] >=3.4"] +build-backend = "setuptools.build_meta" + +[project.entry-points."asdf.extensions"] +mfconverter = "mfconverter.extensions:get_extensions" + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/notebooks/Your_first_ASDF_converter/src/mfconverter/__init__.py b/notebooks/Your_first_ASDF_converter/src/mfconverter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/notebooks/Your_first_ASDF_converter/src/mfconverter/converter.py b/notebooks/Your_first_ASDF_converter/src/mfconverter/converter.py new file mode 100644 index 0000000..792085f --- /dev/null +++ b/notebooks/Your_first_ASDF_converter/src/mfconverter/converter.py @@ -0,0 +1,24 @@ +from asdf.extension import Converter + +class PhotoIDConverter(Converter): + tags = ["asdf://stsci.edu/example-project/tags/photo_id-*"] + types = ["mfconverter.photo_id.PhotoID"] + # The above registers the tag that the converter is used for, as well as + # associating the class that the converter is used for. + + # This method converts from the Python object to yaml + def to_yaml_tree(self, obj, tags, ctx): + # The yaml conversion expects a dictionary returned + node = {} + node['first_name'] = obj.first_name + node['last_name'] = obj.last_name + node['photo'] = obj.photo + return node + + # This method converts from yaml to the Python object + def from_yaml_tree(self, node, tag, ctx): + from .photo_id import PhotoID # Deferred import to avoid always importing + # when ASDF gets entry points. + return PhotoID(node['last_name'], + node['first_name'], + node['photo']) diff --git a/notebooks/Your_first_ASDF_converter/src/mfconverter/extensions.py b/notebooks/Your_first_ASDF_converter/src/mfconverter/extensions.py new file mode 100644 index 0000000..398f111 --- /dev/null +++ b/notebooks/Your_first_ASDF_converter/src/mfconverter/extensions.py @@ -0,0 +1,11 @@ +from asdf.extension import Extension +from .converter import PhotoIDConverter + +class MFExtension(Extension): + extension_uri = "asdf://stsci.edu/example-project/photo_id-1.0.0" + tags = ["asdf://stsci.edu/example-project/tags/photo_id-1.0.0"] + converters = [PhotoIDConverter()] + +# The following will be called by ASDF when looking for ASDF entry points +def get_extensions(): + return [MFExtension()] diff --git a/notebooks/Your_first_ASDF_converter/src/mfconverter/photo_id.py b/notebooks/Your_first_ASDF_converter/src/mfconverter/photo_id.py new file mode 100644 index 0000000..e6d28d3 --- /dev/null +++ b/notebooks/Your_first_ASDF_converter/src/mfconverter/photo_id.py @@ -0,0 +1,11 @@ +class PhotoID: + "Holds Photo ID information" + + def __init__(self, last_name, first_name, photo): + "expects a monochromatic numpy array for photo" + self.last_name = last_name + self.first_name = first_name + self.photo = photo + + def name(self): + return self.last_name + ', ' + self.first_name diff --git a/notebooks/Your_second_ASDF_converter.ipynb b/notebooks/Your_second_ASDF_converter.ipynb index b3c445e..6e7bc84 100644 --- a/notebooks/Your_second_ASDF_converter.ipynb +++ b/notebooks/Your_second_ASDF_converter.ipynb @@ -100,88 +100,6 @@ "First ensure you are in the directory that you want to create both packages in, by default it will be your home directory below, but change it to what you want before executing." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "bb0c1b6e", - "metadata": {}, - "outputs": [], - "source": [ - "cd ~/converter_tutorial\n" - ] - }, - { - "cell_type": "markdown", - "id": "067eed9a", - "metadata": {}, - "source": [ - "The following utility will build a schema package. It will\n", - "prompt for answers to a series of questions. Here is an \n", - "explanation of what is expected for these questions. **You must\n", - "run this utility from a terminal window.** Type the command as\n", - "shown in this directory and provide the answers as shown below.\n", - "If this is rerun you may get an initial prompt mentioning the\n", - "template has been downloaded before; just type return to accept\n", - "the default `yes`\n", - "\n", - "`\n", - "cookiecutter gh:asdf-format/schemas-package-template\n", - "`\n", - "\n", - "`\n", - "package_name [asdf-example-schemas]: myschemas\n", - "`\n", - "\n", - "This will be the directory name it will go in.\n", - "\n", - "`\n", - "module_name [myschemas]: \n", - "`\n", - "\n", - "Accept the default (providing a different answer will create a\n", - "different module name within the package\n", - "\n", - "`\n", - "Short_description [mfconverter]: my first schemas\n", - "`\n", - "\n", - "Self evident\n", - "\n", - "`\n", - "author_name [Author Name]: Bullwinkle Moose\n", - "`\n", - "\n", - "Provide a phony answer. You don't really want people to know who \n", - "wrote this, do you?\n", - "\n", - "`\n", - "author_email [author@example.com]: bullwinkle@stsci.edu\n", - "`\n", - "\n", - "`\n", - "github_project [github-org/myschemas]: [bullwinkle/myschemas]\n", - "`\n", - "\n", - "This won't actually create a repository on github, but is useful\n", - "if you will add it to github\n", - "\n", - "`\n", - "project_url [https://github.com/bullwinkle/myschemas]]: \n", - "`\n", - "\n", - "`\n", - "uri_authority [example.com]: stsci.edu \n", - "`\n", - "\n", - "`\n", - "uri_project [example-project]:\n", - "`\n", - "\n", - "But since this is jupyter-based, we will do part of what it does\n", - "manually later, partly because editing files within jupyter is \n", - "not simple within the notebook for a tutorial." - ] - }, { "cell_type": "markdown", "id": "4dbf7bee", @@ -195,76 +113,6 @@ "handle multiple converters." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "8564c41d", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir ~/converter_tutorial" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e93474e", - "metadata": {}, - "outputs": [], - "source": [ - "cd ~/converter_tutorial" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7f25df85", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir myconverters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e931f085", - "metadata": {}, - "outputs": [], - "source": [ - "pwd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3bbc846f", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir myconverters/src" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a1ca1d34", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir myconverters/src/myconverters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "978d413d", - "metadata": {}, - "outputs": [], - "source": [ - "cd myconverters" - ] - }, { "cell_type": "markdown", "id": "e94f6849", @@ -273,27 +121,6 @@ "Add the usual files" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "61da8bca", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myconverters/photo_id.py\n", - "class PhotoID:\n", - " \"Holds Phot ID information\"\n", - "\n", - " def __init__(self, last_name, first_name, image):\n", - " \"expects a monochromatic numpy array for image\"\n", - " self.last_name = last_name\n", - " self.first_name = first_name\n", - " self.photo = image\n", - " \n", - " def name(self):\n", - " return self.last_name + ', ' + self.first_name" - ] - }, { "cell_type": "markdown", "id": "e318f5c2", @@ -302,109 +129,6 @@ "Add a second class that references the first." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "ff6bd411", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myconverters/traffic_citation.py\n", - "from .photo_id import PhotoID\n", - "\n", - "\n", - "class TrafficCitation:\n", - " \"Record of a traffic violation\"\n", - "\n", - " def __init__(self, ociffer, violation, date, time, photo_id):\n", - " self.ociffer = ociffer\n", - " self.violation = violation\n", - " self.date = date\n", - " self.time = time\n", - " self.photo_id = photo_id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "482ba07e", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myconverters/converters.py\n", - "from asdf.extension import Converter\n", - "from .photo_id import PhotoID\n", - "from .traffic_citation import TrafficCitation\n", - "\n", - "\n", - "class PhotoIDConverter(Converter):\n", - " tags = [\"asdf://stsci.edu/example-project/tags/photo_id-*\"]\n", - " types = [\"myconverters.photo_id.PhotoID\"]\n", - " # The above registers the tag that the converter is used for, as well as\n", - " # associating the class that the converter is used for.\n", - "\n", - " # This method converts from the Python object to yaml\n", - " def to_yaml_tree(self, obj, tags, ctx):\n", - " # The yaml conversion expects a dictionary returned\n", - " node = {}\n", - " node['first_name'] = obj.first_name\n", - " node['last_name'] = obj.last_name\n", - " node['photo'] = obj.photo\n", - " return node\n", - "\n", - " # This method converts from yaml to the Python object\n", - " def from_yaml_tree(self, node, tag, ctx):\n", - " return PhotoID(node['last_name'],\n", - " node['first_name'],\n", - " node['photo'])\n", - "\n", - "\n", - "class TrafficCitationConverter(Converter):\n", - " tags = [\"asdf://stsci.edu/example-project/tags/traffic_citation-1.0.0\"]\n", - " types = [\"myconverters.traffic_citation.TrafficCitation\"]\n", - "\n", - " def to_yaml_tree(self, obj, tags, ctx):\n", - " node = {}\n", - " node['ociffer'] = obj.ociffer\n", - " node['violation'] = obj.violation\n", - " node['date'] = obj.date\n", - " node['time'] = obj.time\n", - " node['photo_id'] = obj.photo_id\n", - " return node\n", - "\n", - " def from_yaml_tree(self, node, tag, ctx):\n", - " return TrafficCitation(node['ociffer'],\n", - " node['violation'],\n", - " node['date'],\n", - " node['time'],\n", - " node['photo_id'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6d5ff931", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myconverters/extensions.py\n", - "from asdf.extension import ManifestExtension\n", - "from .converters import (\n", - " PhotoIDConverter,\n", - " TrafficCitationConverter,)\n", - "\n", - "MY_CONVERTERS = [\n", - " PhotoIDConverter(),\n", - " TrafficCitationConverter(),\n", - "]\n", - "\n", - "MY_EXTENSIONS = [\n", - " ManifestExtension.from_uri(\n", - " \"asdf://stsci.edu/example-project/manifests/allmyschemas-1.0\",\n", - " converters=MY_CONVERTERS)\n", - "]" - ] - }, { "cell_type": "markdown", "id": "fa724a37", @@ -419,19 +143,6 @@ "module's entry point." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "1d09bd82", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myconverters/integration.py\n", - "def get_extensions():\n", - " from . import extensions\n", - " return extensions.MY_EXTENSIONS" - ] - }, { "cell_type": "markdown", "id": "4577bcd7", @@ -440,17 +151,6 @@ "Add the `__init__.py`" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "99753484", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myconverters/__init__.py\n", - "\n" - ] - }, { "cell_type": "markdown", "id": "799981ad", @@ -459,51 +159,6 @@ "And now to add the setup files. Note the change to integrations.py for get_extensions" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "b82c5f58", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile pyproject.toml\n", - "[project]\n", - "name = \"myconverters\"\n", - "description = \"TODO\"\n", - "version='0.1.0'\n", - "requires-python = \">=3.9\"\n", - "dependencies = [\n", - " \"jsonschema >=3.0.2\",\n", - " \"asdf >=2.8\",\n", - " \"psutil >=5.7.2\",\n", - " \"numpy>=1.16\",\n", - "]\n", - "\n", - "[build-system]\n", - "requires = [\"setuptools >=61\", \"setuptools_scm[toml] >=3.4\"]\n", - "build-backend = \"setuptools.build_meta\"\n", - "\n", - "[project.entry-points.\"asdf.extensions\"]\n", - "myconverters = \"myconverters.integration:get_extensions\"\n", - "\n", - "[tool.setuptools.packages.find]\n", - "where = [\"src\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ebbffa3", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile setup.py\n", - "#!/usr/bin/env python3\n", - "from setuptools import setup\n", - "\n", - "setup()" - ] - }, { "cell_type": "markdown", "id": "21c2ef73", @@ -516,86 +171,6 @@ "Only the strictly necessary parts will be done manually, partly to minimize what has to be done, but also it isn't easy to edit files in a tutorial notebook." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "02fb0e4b", - "metadata": {}, - "outputs": [], - "source": [ - "cd .." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "28402214", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir myschemas" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "308c46c1", - "metadata": {}, - "outputs": [], - "source": [ - "cd myschemas" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a36535a5", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fd3a8d6b", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src/myschemas" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "886f2ccc", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src/myschemas/resources" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0009d892", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src/myschemas/resources/manifests" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "146a9a4c", - "metadata": {}, - "outputs": [], - "source": [ - "mkdir src/myschemas/resources/schemas" - ] - }, { "cell_type": "markdown", "id": "90720a6a", @@ -604,20 +179,6 @@ "Create the setup files" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "32e10f16", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile setup.py\n", - "#!/usr/bin/env python3\n", - "from setuptools import setup\n", - "\n", - "setup()" - ] - }, { "cell_type": "markdown", "id": "2e0e88f6", @@ -631,119 +192,6 @@ "will follow the creation of the schemas." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "973a0a41-9639-4a21-8465-0d76c656dc3d", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile pyproject.toml\n", - "[project]\n", - "name = \"myschemas\"\n", - "description = \"Schemas for second converter tutorial\"\n", - "version='0.1.0'\n", - "requires-python = \">=3.9\"\n", - "dependencies = [\n", - " \"jsonschema >=3.0.2\",\n", - " \"asdf >=2.8\",\n", - " \"psutil >=5.7.2\",\n", - " \"numpy >=1.16\",\n", - "]\n", - "\n", - "[build-system]\n", - "requires = [\"setuptools >=61\", \"setuptools_scm[toml] >=3.4\"]\n", - "build-backend = \"setuptools.build_meta\"\n", - "\n", - "[project.entry-points.\"asdf.resource_mappings\"]\n", - "myschema = \"myschemas.integration:get_resource_mappings\"\n", - "\n", - "[project.entry-points.\"asdf.extensions\"]\n", - "myconverter = \"myconverters.integration:get_extensions\"\n", - "\n", - "[tool.package-data]\n", - "\"myschema.resources\" = [\n", - " \"manifests/*.yaml\",\n", - " \"schemas/*.yaml\",\n", - "]\n", - "\n", - "[tool.setuptools.packages.find]\n", - "where = [\"src\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b53eac2", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myschemas/resources/schemas/photo_id-1.0.0.yaml\n", - "%YAML 1.1\n", - "---\n", - "$schema: \"http://stsci.edu/schemas/yaml-schema/draft-01\"\n", - "id: asdf://stsci.edu/example-project/schemas/photo_id-1.0.0\n", - "\n", - "title: Photo ID information\n", - "type: object\n", - "properties:\n", - " last_name:\n", - " title: Last name of the ID holder\n", - " type: string\n", - " first_name:\n", - " title: First name of ID holder\n", - " type: string\n", - " photo:\n", - " title: Monochromatic photo of ID holder\n", - " tag: tag:stsci.edu:asdf/core/ndarray-1.0.0\n", - " datatype: int8\n", - " ndim: 2\n", - "\n", - "propertyOrder: [last_name, first_name, photo]\n", - "flowStyle: block\n", - "required: [last_name, first_name, photo]\n", - "...\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee0ecaff", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myschemas/resources/schemas/traffic_citation-1.0.0.yaml\n", - "%YAML 1.1\n", - "---\n", - "$schema: \"http://stsci.edu/schemas/yaml-schema/draft-01\"\n", - "id: asdf://stsci.edu/example-project/schemas/traffic_citation-1.0.0\n", - "\n", - "title: Traffic Citation Information\n", - "type: object\n", - "properties:\n", - " ociffer:\n", - " title: Name of ociffer issuing citation\n", - " type: string\n", - " violation:\n", - " title: Type of traffic violation\n", - " type: string\n", - " enum: [\"speeding\", \"DWI\", \"Failure to Signal\", \"Driving like a jerk\"]\n", - " date:\n", - " title: Date of violation\n", - " type: string \n", - " time:\n", - " title: Time of day of violation\n", - " type: string\n", - " photo_id:\n", - " title: photo_id of the driver committing violation\n", - " tag: asdf://stsci.edu/example-project/tags/photo_id-1.0.0\n", - "\n", - "propertyOrder: [ociffer, violation, date, time, photo_id]\n", - "flowStyle: block\n", - "required: [ociffer, violation, date, time, photo_id]\n", - "...\n" - ] - }, { "cell_type": "markdown", "id": "a3cc78f3", @@ -849,39 +297,6 @@ "between different types." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "bac28bcc", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myschemas/resources/manifests/allmyschemas-1.0.yaml\n", - "%YAML 1.1\n", - "---\n", - "id: asdf://stsci.edu/example-project/manifests/allmyschemas-1.0\n", - "extension_uri: asdf://stsci.edu/example-project/extensions/allmyschemas-1.0\n", - "title: All my schemas 1.0\n", - "description: |-\n", - " A set of tags for serializing all my schemas.\n", - "asdf_standard_requirement:\n", - " gte: 1.1.0\n", - "tags:\n", - "# Object Modules\n", - "- tag_uri: asdf://stsci.edu/example-project/tags/photo_id-1.0.0\n", - " schema_uri: asdf://stsci.edu/example-project/schemas/photo_id-1.0.0\n", - " title: Photo ID information\n", - " description: |-\n", - " Name on Photo ID and the photo from the Photo ID\n", - "- tag_uri: asdf://stsci.edu/example-project/tags/traffic_citation-1.0.0\n", - " schema_uri: asdf://stsci.edu/example-project/schemas/traffic_citation-1.0.0\n", - " title: Information about an issued traffic citation\n", - " description: |-\n", - " Information about an issued traffic citation including ociffer name, type of violation,\n", - " date, time, and photo ID.\n", - "...\n" - ] - }, { "cell_type": "markdown", "id": "81338de6", @@ -896,45 +311,6 @@ "that." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "6c3c2d92", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myschemas/integration.py\n", - "import sys\n", - "\n", - "from asdf.resource import DirectoryResourceMapping\n", - "\n", - "if sys.version_info < (3, 9):\n", - " import importlib_resources\n", - "else:\n", - " import importlib.resources as importlib_resources\n", - "\n", - "\n", - "def get_resource_mappings():\n", - " \"\"\"\n", - " Get the resource mapping instances for myschemas\n", - " and manifests. This method is registered with the\n", - " asdf.resource_mappings entry point.\n", - "\n", - " Returns\n", - " -------\n", - " list of collections.abc.Mapping\n", - " \"\"\"\n", - " from . import resources\n", - " resources_root = importlib_resources.files(resources)\n", - "\n", - " return [\n", - " DirectoryResourceMapping(\n", - " resources_root / \"schemas\", \"asdf://stsci.edu/example-project/schemas/\"),\n", - " DirectoryResourceMapping(\n", - " resources_root / \"manifests\", \"asdf://stsci.edu/example-project/manifests/\"),\n", - " ]\n" - ] - }, { "cell_type": "markdown", "id": "2f70eef1", @@ -956,28 +332,6 @@ "this a package." ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "d47a1b5e", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myschemas/__init__.py\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ebb6630a", - "metadata": {}, - "outputs": [], - "source": [ - "%%writefile src/myschemas/resources/__init__.py\n", - "\n" - ] - }, { "cell_type": "markdown", "id": "e5b7344a", @@ -987,26 +341,6 @@ "---------------------------" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "4a67e777", - "metadata": {}, - "outputs": [], - "source": [ - "pip install --editable ." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8261435e", - "metadata": {}, - "outputs": [], - "source": [ - "cd ../myconverters" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1014,7 +348,7 @@ "metadata": {}, "outputs": [], "source": [ - "pip install --editable ." + "pip install ./Your_second_ASDF_converter" ] }, { @@ -1143,6 +477,7 @@ "metadata": {}, "outputs": [], "source": [ + "# NBVAL_RAISES_EXCEPTION\n", "af2.write_to('test2.asdf')" ] }, @@ -1181,7 +516,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.10" + "version": "3.13.4" } }, "nbformat": 4, diff --git a/notebooks/Your_second_ASDF_converter/pyproject.toml b/notebooks/Your_second_ASDF_converter/pyproject.toml new file mode 100644 index 0000000..358d98c --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/pyproject.toml @@ -0,0 +1,18 @@ +[project] +name = "myconverters" +description = "TODO" +version='0.1.0' +requires-python = ">=3.9" +dependencies = [ + "asdf >=2.8", +] + +[build-system] +requires = ["setuptools >=61", "setuptools_scm[toml] >=3.4"] +build-backend = "setuptools.build_meta" + +[project.entry-points."asdf.resource_mappings"] +myschema = "myschemas.integration:get_resource_mappings" + +[project.entry-points."asdf.extensions"] +myconverters = "myconverters.integration:get_extensions" diff --git a/notebooks/Your_second_ASDF_converter/src/myconverters/__init__.py b/notebooks/Your_second_ASDF_converter/src/myconverters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/notebooks/Your_second_ASDF_converter/src/myconverters/converters.py b/notebooks/Your_second_ASDF_converter/src/myconverters/converters.py new file mode 100644 index 0000000..2012e07 --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myconverters/converters.py @@ -0,0 +1,46 @@ +from asdf.extension import Converter +from .photo_id import PhotoID +from .traffic_citation import TrafficCitation + + +class PhotoIDConverter(Converter): + tags = ["asdf://stsci.edu/example-project/tags/photo_id-*"] + types = ["myconverters.photo_id.PhotoID"] + # The above registers the tag that the converter is used for, as well as + # associating the class that the converter is used for. + + # This method converts from the Python object to yaml + def to_yaml_tree(self, obj, tags, ctx): + # The yaml conversion expects a dictionary returned + node = {} + node['first_name'] = obj.first_name + node['last_name'] = obj.last_name + node['photo'] = obj.photo + return node + + # This method converts from yaml to the Python object + def from_yaml_tree(self, node, tag, ctx): + return PhotoID(node['last_name'], + node['first_name'], + node['photo']) + + +class TrafficCitationConverter(Converter): + tags = ["asdf://stsci.edu/example-project/tags/traffic_citation-1.0.0"] + types = ["myconverters.traffic_citation.TrafficCitation"] + + def to_yaml_tree(self, obj, tags, ctx): + node = {} + node['ociffer'] = obj.ociffer + node['violation'] = obj.violation + node['date'] = obj.date + node['time'] = obj.time + node['photo_id'] = obj.photo_id + return node + + def from_yaml_tree(self, node, tag, ctx): + return TrafficCitation(node['ociffer'], + node['violation'], + node['date'], + node['time'], + node['photo_id']) diff --git a/notebooks/Your_second_ASDF_converter/src/myconverters/extensions.py b/notebooks/Your_second_ASDF_converter/src/myconverters/extensions.py new file mode 100644 index 0000000..9b81058 --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myconverters/extensions.py @@ -0,0 +1,15 @@ +from asdf.extension import ManifestExtension +from .converters import ( + PhotoIDConverter, + TrafficCitationConverter,) + +MY_CONVERTERS = [ + PhotoIDConverter(), + TrafficCitationConverter(), +] + +MY_EXTENSIONS = [ + ManifestExtension.from_uri( + "asdf://stsci.edu/example-project/manifests/allmyschemas-1.0", + converters=MY_CONVERTERS) +] diff --git a/notebooks/Your_second_ASDF_converter/src/myconverters/integration.py b/notebooks/Your_second_ASDF_converter/src/myconverters/integration.py new file mode 100644 index 0000000..2745dcb --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myconverters/integration.py @@ -0,0 +1,3 @@ +def get_extensions(): + from . import extensions + return extensions.MY_EXTENSIONS diff --git a/notebooks/Your_second_ASDF_converter/src/myconverters/photo_id.py b/notebooks/Your_second_ASDF_converter/src/myconverters/photo_id.py new file mode 100644 index 0000000..3fe621e --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myconverters/photo_id.py @@ -0,0 +1,11 @@ +class PhotoID: + "Holds Phot ID information" + + def __init__(self, last_name, first_name, image): + "expects a monochromatic numpy array for image" + self.last_name = last_name + self.first_name = first_name + self.photo = image + + def name(self): + return self.last_name + ', ' + self.first_name diff --git a/notebooks/Your_second_ASDF_converter/src/myconverters/traffic_citation.py b/notebooks/Your_second_ASDF_converter/src/myconverters/traffic_citation.py new file mode 100644 index 0000000..b61cee9 --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myconverters/traffic_citation.py @@ -0,0 +1,12 @@ +from .photo_id import PhotoID + + +class TrafficCitation: + "Record of a traffic violation" + + def __init__(self, ociffer, violation, date, time, photo_id): + self.ociffer = ociffer + self.violation = violation + self.date = date + self.time = time + self.photo_id = photo_id diff --git a/notebooks/Your_second_ASDF_converter/src/myschemas/__init__.py b/notebooks/Your_second_ASDF_converter/src/myschemas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/notebooks/Your_second_ASDF_converter/src/myschemas/integration.py b/notebooks/Your_second_ASDF_converter/src/myschemas/integration.py new file mode 100644 index 0000000..25f3a6c --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myschemas/integration.py @@ -0,0 +1,26 @@ +import sys + +from asdf.resource import DirectoryResourceMapping + +import importlib.resources as importlib_resources + + +def get_resource_mappings(): + """ + Get the resource mapping instances for myschemas + and manifests. This method is registered with the + asdf.resource_mappings entry point. + + Returns + ------- + list of collections.abc.Mapping + """ + from . import resources + resources_root = importlib_resources.files(resources) + + return [ + DirectoryResourceMapping( + resources_root / "schemas", "asdf://stsci.edu/example-project/schemas/"), + DirectoryResourceMapping( + resources_root / "manifests", "asdf://stsci.edu/example-project/manifests/"), + ] diff --git a/notebooks/Your_second_ASDF_converter/src/myschemas/resources/__init__.py b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/notebooks/Your_second_ASDF_converter/src/myschemas/resources/manifests/allmyschemas-1.0.yaml b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/manifests/allmyschemas-1.0.yaml new file mode 100644 index 0000000..731d84d --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/manifests/allmyschemas-1.0.yaml @@ -0,0 +1,23 @@ +%YAML 1.1 +--- +id: asdf://stsci.edu/example-project/manifests/allmyschemas-1.0 +extension_uri: asdf://stsci.edu/example-project/extensions/allmyschemas-1.0 +title: All my schemas 1.0 +description: |- + A set of tags for serializing all my schemas. +asdf_standard_requirement: + gte: 1.1.0 +tags: +# Object Modules +- tag_uri: asdf://stsci.edu/example-project/tags/photo_id-1.0.0 + schema_uri: asdf://stsci.edu/example-project/schemas/photo_id-1.0.0 + title: Photo ID information + description: |- + Name on Photo ID and the photo from the Photo ID +- tag_uri: asdf://stsci.edu/example-project/tags/traffic_citation-1.0.0 + schema_uri: asdf://stsci.edu/example-project/schemas/traffic_citation-1.0.0 + title: Information about an issued traffic citation + description: |- + Information about an issued traffic citation including ociffer name, type of violation, + date, time, and photo ID. +... diff --git a/notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/photo_id-1.0.0.yaml b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/photo_id-1.0.0.yaml new file mode 100644 index 0000000..b554024 --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/photo_id-1.0.0.yaml @@ -0,0 +1,24 @@ +%YAML 1.1 +--- +$schema: "http://stsci.edu/schemas/yaml-schema/draft-01" +id: asdf://stsci.edu/example-project/schemas/photo_id-1.0.0 + +title: Photo ID information +type: object +properties: + last_name: + title: Last name of the ID holder + type: string + first_name: + title: First name of ID holder + type: string + photo: + title: Monochromatic photo of ID holder + tag: tag:stsci.edu:asdf/core/ndarray-1.0.0 + datatype: int8 + ndim: 2 + +propertyOrder: [last_name, first_name, photo] +flowStyle: block +required: [last_name, first_name, photo] +... diff --git a/notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/traffic_citation-1.0.0.yaml b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/traffic_citation-1.0.0.yaml new file mode 100644 index 0000000..98bee7c --- /dev/null +++ b/notebooks/Your_second_ASDF_converter/src/myschemas/resources/schemas/traffic_citation-1.0.0.yaml @@ -0,0 +1,29 @@ +%YAML 1.1 +--- +$schema: "http://stsci.edu/schemas/yaml-schema/draft-01" +id: asdf://stsci.edu/example-project/schemas/traffic_citation-1.0.0 + +title: Traffic Citation Information +type: object +properties: + ociffer: + title: Name of ociffer issuing citation + type: string + violation: + title: Type of traffic violation + type: string + enum: ["speeding", "DWI", "Failure to Signal", "Driving like a jerk"] + date: + title: Date of violation + type: string + time: + title: Time of day of violation + type: string + photo_id: + title: photo_id of the driver committing violation + tag: asdf://stsci.edu/example-project/tags/photo_id-1.0.0 + +propertyOrder: [ociffer, violation, date, time, photo_id] +flowStyle: block +required: [ociffer, violation, date, time, photo_id] +... diff --git a/tox.ini b/tox.ini index c988e5e..8e256ff 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,5 @@ deps = -rrequirements.txt pytest nbval -# don't install a package -install_command = commands = pytest --nbval From 4366eeaeea7a9ae4657297936a42d562b2e1a449 Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 6 Aug 2025 16:58:59 -0400 Subject: [PATCH 2/3] update package description in converter notebook --- notebooks/Your_first_ASDF_converter.ipynb | 64 +++++------------------ 1 file changed, 12 insertions(+), 52 deletions(-) diff --git a/notebooks/Your_first_ASDF_converter.ipynb b/notebooks/Your_first_ASDF_converter.ipynb index 4a01dbc..0da5ce0 100644 --- a/notebooks/Your_first_ASDF_converter.ipynb +++ b/notebooks/Your_first_ASDF_converter.ipynb @@ -29,7 +29,7 @@ "a Python object equivalent to the one it started out as.\n", "\n", "Note: The object to be serialized to ASDF must consist\n", - "of only elements that ADSF knows how to serialize. ASDF does\n", + "of only elements that asdf knows how to serialize. asdf does\n", "know how to serialize numpy arrays and all standard \n", "Python primative types (e.g., strings, numbers, booleans,\n", "lists and dictionaries), as well as objects that have \n", @@ -54,18 +54,15 @@ "--------------\n", "\n", "For ASDF to be aware of the converters, it is necessary \n", - "to include in the setup.cfg file information for an entry\n", + "to configure an entry\n", "point for ASDF. Entry points are\n", - "a very useful Python tool for making plug-ins for packages\n", - "easy for users of the plug-in to use, both in the installation\n", + "a useful Python tool for making plug-ins easy for users, both in the installation\n", "and usage aspect.\n", "Entry points remove the need for the core package to be continually \n", "updated with new extension packages that it has to be aware of.\n", "\n", "This information is provided in the converter package's\n", - "setup.cfg (it could be in\n", - "setup.py, but the .cfg file is the usual place to put this\n", - "information). What happens when the package is installed is\n", + "configuration. What happens when the package is installed is\n", "that information about entry points is saved by Python. Python\n", "provides an API to the core package for it to discover what \n", "entry points have been designated for that package so that it can\n", @@ -80,26 +77,7 @@ "We will name the converter package mfconverter (for My First\n", "Converter) so this will create a package of that name in\n", "the current directory. This tutorial will have the bare bones\n", - "files needed for that. The following will generate\n", - "such a barebones directory structure.\n", - "\n", - "Since this tutorial effectively is editing files and needs\n", - "to move between different directories, it is more awkward than\n", - "usual for a notebook\n", - "\n", - "Required Software\n", - "----------------------\n", - "\n", - "- numpy\n", - "- asdf v2.8 or higher\n", - "\n", - "Let's begin\n", - "-------------\n", - "\n", - "This will create a converter_tutorial directory in your home directory.\n", - "If you wish it to be elsewhere, make the appropriate changes to the\n", - "dependent commands, but if there is no strong reason to change it,\n", - "leave it be." + "files needed for that." ] }, { @@ -107,15 +85,7 @@ "id": "ede348bd", "metadata": {}, "source": [ - "And now we will create a module that has a very, very simple photo ID class and add a package `__init__.py`" - ] - }, - { - "cell_type": "markdown", - "id": "09ee1385", - "metadata": {}, - "source": [ - "Next we create the file that contains the converter code" + "The files for `mfconverter` are located in the `Your_first_ASDF_converter` directory alongside this notebook. Please review the files. A few specific details will be highlighted below." ] }, { @@ -123,20 +93,18 @@ "id": "55ca30cd", "metadata": {}, "source": [ - "In the above example, the class attribute `types` is a list since it is\n", + "In `PhotoIDConverter` defined in `converter.py`, the class attribute `types` is a list since it is\n", "possible for multiple types to use the same converter. Secondly, it is\n", "possible to supply the type as either a string (as done above) as the \n", "actual class itself. The former is preferred for peformance reasons as\n", "using the actual class itself forces the ASDF package to import the\n", "module containing the class, even if it is never used in the program\n", - "using ASDF.\n", + "using asdf.\n", "\n", "The wildcard for the tag entry indicates that this converter will work\n", "with all versions of the tag. It isn't strictly needed here, but generally \n", "a good practice if one wants the converter code to handle multiple versions.\n", - "(How to handle versioning is a topic in its own right and not covered here)\n", - "\n", - "We need to create a module for the entry point handling" + "(How to handle versioning is a topic in its own right and not covered here)" ] }, { @@ -144,18 +112,10 @@ "id": "412c3e4f", "metadata": {}, "source": [ - "And finally, the entry point reference in setup.cfg, provided here as a whole file." - ] - }, - { - "cell_type": "markdown", - "id": "8d0e3882", - "metadata": {}, - "source": [ - "If you wish to learn more about entry points, see:\n", - "https://packaging.python.org/guides/creating-and-discovering-plugins/\n", + "As mentioned above `mfconverter` defines an entry point in the `pyproject.toml` configurate file that is used to register `PhotoIDConverter` with asdf.\n", "\n", - "We need the setup.py file too" + "If you wish to learn more about entry points, see:\n", + "https://packaging.python.org/guides/creating-and-discovering-plugins/" ] }, { From a2b226ece3c812396916aff1397d11c2fdd3d91b Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 6 Aug 2025 17:12:46 -0400 Subject: [PATCH 3/3] clean up package description in second converter notebook --- notebooks/Your_second_ASDF_converter.ipynb | 154 +++------------------ 1 file changed, 17 insertions(+), 137 deletions(-) diff --git a/notebooks/Your_second_ASDF_converter.ipynb b/notebooks/Your_second_ASDF_converter.ipynb index 6e7bc84..fe5a84c 100644 --- a/notebooks/Your_second_ASDF_converter.ipynb +++ b/notebooks/Your_second_ASDF_converter.ipynb @@ -44,9 +44,7 @@ "that are not in Python). Doing so adds some added complexity,\n", "so this tutorial is aimed mostly at those that will be writing\n", "schemas for pipeline code that generate products that should\n", - "not intrinsically require Python to read. (A separate tutorial\n", - "may be written for cases where schemas are desired, but only \n", - "for Python).\n", + "not intrinsically require Python to read.\n", "\n", "It takes a bit of effort to understand how to write schemas. \n", "If they seem odd and a bit confusing, that is normal. They \n", @@ -69,35 +67,7 @@ "the schemas are not tied directly to Python; but note there\n", "will be a small amount of code in the schema package for Python,\n", "and we expect that if other languages are used, code for those\n", - "may appear there as well).\n", - "\n", - "A utility has been developed so that the schema package is \n", - "fairly easily generated and this tutorial will use that utility.\n", - "The structure of the converter package will be very similar to\n", - "that of the first tutorial.\n", - "\n", - "Required Software\n", - "---------------------\n", - "\n", - "- numpy\n", - "- asdf v2.8 or higher\n", - "\n", - "The following is recommended when creating your own package but \n", - "not directly needed for this tutorial\n", - "\n", - "- cookiecutter (do a `pip install cookiecutter`)\n", - "\n", - "Software uninstall\n", - "---------------------\n", - "\n", - "If you did the first tutorial (Your_first_ASDF_converter), in a terminal window \n", - "type `pip uninstall mfconverter` since this tutorial will reuse the same \n", - "photoID class and we don't want confusion between the two converters.\n", - "\n", - "Create schema package\n", - "----------------------------\n", - "\n", - "First ensure you are in the directory that you want to create both packages in, by default it will be your home directory below, but change it to what you want before executing." + "may appear there as well)." ] }, { @@ -110,53 +80,12 @@ "\n", "This will be similar to the first tutorial, but with some changes\n", "the structure. There will be two converters to illustrate how to\n", - "handle multiple converters." - ] - }, - { - "cell_type": "markdown", - "id": "e94f6849", - "metadata": {}, - "source": [ - "Add the usual files" - ] - }, - { - "cell_type": "markdown", - "id": "e318f5c2", - "metadata": {}, - "source": [ - "Add a second class that references the first." - ] - }, - { - "cell_type": "markdown", - "id": "fa724a37", - "metadata": {}, - "source": [ - "Notice the changes to the last file as compared to the first tutorial.\n", - "Now it references a manifest that is elsewhere and provides a list\n", - "of converter instances instead. This manifest will be located in the\n", - "schema package and is used to associate schemas with tags.\n", + "handle multiple converters.\n", "\n", - "In addition, an additional file is created for the purposes of this\n", - "module's entry point." - ] - }, - { - "cell_type": "markdown", - "id": "4577bcd7", - "metadata": {}, - "source": [ - "Add the `__init__.py`" - ] - }, - { - "cell_type": "markdown", - "id": "799981ad", - "metadata": {}, - "source": [ - "And now to add the setup files. Note the change to integrations.py for get_extensions" + "The files for this tutorial are located in `Your_second_ASDF_converter`. The `myconverters` package is similar to the one covered in `Your_first_ASDF_converter` with some notable changes:\n", + "- The extension is registered using the manifest (covered below) see `myconverters/extensions.py`\n", + "- `myconveters/converters.py` contains 2 converters\n", + "- `myconverters.integration.get_extensions` is registered via the `asdf.extensions` entry point" ] }, { @@ -166,30 +95,12 @@ "source": [ "Dealing with the Schemas\n", "------------------------------\n", - "The utility previously mentioned would have contructed a directory tree for us with many files populated\n", "\n", - "Only the strictly necessary parts will be done manually, partly to minimize what has to be done, but also it isn't easy to edit files in a tutorial notebook." - ] - }, - { - "cell_type": "markdown", - "id": "90720a6a", - "metadata": {}, - "source": [ - "Create the setup files" - ] - }, - { - "cell_type": "markdown", - "id": "2e0e88f6", - "metadata": {}, - "source": [ + "The schemas for this notebook are provided through the `myschemas` package in the `Your_second_ASDF_converter` directory.\n", + "\n", "Note that the form of the entry points is different now that schemas are involved.\n", "Also there is a need to add an indication that the schema and manefits files must\n", - "installed along with the software.\n", - "\n", - "Now create the two needed schema files. The explanation of how the schema works\n", - "will follow the creation of the schemas." + "installed along with the software." ] }, { @@ -287,14 +198,7 @@ " # only have four allowed values, those listed for enum. Any other \n", " # value will cause a validation error.\n", " enum: [\"speeding\", \"DWI\", \"Failure to Signal\", \"Driving like a jerk\"]\n", - "```\n", - "\n", - "The rest of the content of this package involves making the necessary\n", - "connections to ASDF and to the associated tags.\n", - "\n", - "We will start with the manifest file. This file makes it simpler to \n", - "put all the connections in one place, and it allows sharing schemas\n", - "between different types." + "```" ] }, { @@ -302,20 +206,12 @@ "id": "81338de6", "metadata": {}, "source": [ + "The rest of the content of `myschemas` involves making the necessary\n", + "connections to asdf and to the associated tags. This is primarily defined\n", + "in the manifest file (which maps tags and schemas).\n", "\n", + "The manifests and schemas are registered with asdf using `DirectoryResourceMapping` instances defined in `integration.py`.\n", "\n", - "Note that the manifest associates a tag with a schema, and ASDF will use\n", - "that to map from one to the other.\n", - "\n", - "The last file to add is the Python code used for entry points to do just\n", - "that." - ] - }, - { - "cell_type": "markdown", - "id": "2f70eef1", - "metadata": {}, - "source": [ "The key element in this file are the last few lines. What this is \n", "indicating is that when a schema id is encountered and the beginning\n", "of that schema_id matches the last string, the remainder of that\n", @@ -326,10 +222,7 @@ "Likewise for the manifest, where the manifest id is located in the \n", "extensions.py file for the converter package. Basically, it tells the\n", "converter package, where the manifest file may be found on the filesystem,\n", - "and from that, where the schemas may be found on the local filesystem.\n", - "\n", - "Did we say last file? Not quite. We need an empty `__init__.py` to make\n", - "this a package." + "and from that, where the schemas may be found on the local filesystem." ] }, { @@ -357,20 +250,7 @@ "metadata": {}, "source": [ "Testing the converters\n", - "--------------------------\n", - "\n", - "**Now restart the kernel as was done in the first converter tutorial**\n", - "----------------------------------------------------------------------" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d89252f0", - "metadata": {}, - "outputs": [], - "source": [ - "cd ~" + "--------------------------" ] }, {