🚀 Testen Sie Zilliz Cloud, die vollständig verwaltete Milvus, kostenlos – erleben Sie 10x schnellere Leistung! Jetzt testen>>

milvus-logo
LFAI

Überblick

  • Engineering
September 15, 2021
Zhen Chen

Überblick

Projekt-URL: https://github.com/milvus-io/milvus_cli

Vorbereitung: Python3.8, Click 8.0.x

Befehle gruppieren

Erstellen eines Befehls

import click
from utils import PyOrm

@click.group(no_args_is_help=False, add_help_option=False, invoke_without_command=True)
@click.pass_context
def cli(ctx):
    """Milvus CLI"""
    ctx.obj = PyOrm() # PyOrm is a util class which wraps the milvus python SDK. You can pass any class instance here. Any command function passed by @click.obj can call it.

if __name__ == '__main__':
    cli()

Wie im obigen Code verwenden wir @click.group(), um eine Befehlsgruppe cli als Einstiegspunkt zu erstellen. Um eine Eingabeaufforderung (CLI) zu implementieren, müssen wir die Hilfemeldungen für den Eintrag deaktivieren, also fügen wir no_args_is_help=False, add_help_option=False und invoke_without_command=True hinzu. Wenn wir cli nur in das Terminal eingeben, wird nichts gedruckt.

Außerdem verwenden wir @click.pass_context, um einen Kontext für die weitere Verwendung an diese Gruppe zu übergeben.

Erstellen Sie einen Unterbefehl der Befehlsgruppe

Dann fügen wir den ersten Unterbefehl help unter cli ein:

# Print the help message of specified command.
def print_help_msg(command):
    with click.Context(command) as ctx:
        click.echo(command.get_help(ctx))


# Use @cli.command() to create a sub command of cli.
@cli.command()
def help():
    """Show help messages."""
    # Print help message of cli.
    click.echo(print_help_msg(cli))

Jetzt können wir cli help im Terminal verwenden:

$ python milvus_cli/scripts/milvus_cli.py help

Eine Untergruppe einer Befehlsgruppe erstellen

Wir wollen nicht nur einen Unterbefehl wie cli help haben, sondern wir brauchen auch Untergruppenbefehle wie cli list collection, cli list partition und cli list indexes.

Zuerst erstellen wir einen Untergruppenbefehl list, hier können wir den ersten Parameter an @cli.group als Befehlsname übergeben, anstatt den Standardfunktionsnamen zu verwenden, so dass wir doppelte Funktionsnamen reduzieren können.

Achtung, hier verwenden wir @cli.group() anstelle von @click.group, damit wir eine Untergruppe der Ursprungsgruppe erstellen.

Dann verwenden wir @click.pass_obj, um context.obj an die Unterbefehle dieser Untergruppe zu übergeben.

@cli.group('list', no_args_is_help=False)
@click.pass_obj
def listDetails(obj):
    """List collections, partitions and indexes."""
    pass

Dann fügen wir einige Unterbefehle in diese Untergruppe mit @listDetails.command() (nicht @cli.command()) ein. Dies ist nur ein Beispiel, Sie können die Implementierung ignorieren und wir werden sie später besprechen.

@listDetails.command()
@click.option('--timeout', 'timeout', help="[Optional] - An optional duration of time in seconds to allow for the RPC. When timeout is set to None, client waits until server response or error occur.", default=None)
@click.option('--show-loaded', 'showLoaded', help="[Optional] - Only show loaded collections.", default=False)
@click.pass_obj
def collections(obj, timeout, showLoaded):
    """List all collections."""
    try:
        obj.checkConnection()
        click.echo(obj.listCollections(timeout, showLoaded))
    except Exception as e:
        click.echo(message=e, err=True)


@listDetails.command()
@click.option('-c', '--collection', 'collection', help='The name of collection.', default='')
@click.pass_obj
def partitions(obj, collection):
    """List all partitions of the specified collection."""
    try:
        obj.checkConnection()
        validateParamsByCustomFunc(
            obj.getTargetCollection, 'Collection Name Error!', collection)
        click.echo(obj.listPartitions(collection))
    except Exception as e:
        click.echo(message=e, err=True)

Nachdem all diese Schritte abgeschlossen sind, haben wir eine Miltigruppe, die wie folgt aussieht:

image Bild

Einen Befehl anpassen

Optionen hinzufügen

Sie können einem Befehl einige Optionen hinzufügen, die dann wie cli --test-option value verwendet werden.

Hier ist ein Beispiel, wir fügen drei Optionen alias, host und port hinzu, um eine Adresse für die Verbindung mit Milvus anzugeben.

Die ersten beiden Parameter definieren den kurzen und den vollständigen Namen der Option, der dritte Parameter definiert den Variablennamen, der Parameter help spezifiziert die kurze Hilfemeldung, der Parameter default spezifiziert den Standardwert und der Parameter type spezifiziert den Wertetyp.

Die Werte aller Optionen werden in der Reihenfolge ihrer Definition an die Funktion übergeben.

@cli.command(no_args_is_help=False)
@click.option('-a', '--alias', 'alias', help="Milvus link alias name, default is `default`.", default='default', type=str)
@click.option('-h', '--host', 'host', help="Host name, default is `127.0.0.1`.", default='127.0.0.1', type=str)
@click.option('-p', '--port', 'port', help="Port, default is `19530`.", default=19530, type=int)
@click.pass_obj
def connect(obj, alias, host, port):
    pass

Flaggenoptionen hinzufügen

Wir verwenden die obigen Optionen, um einen Wert zu übergeben, aber manchmal brauchen wir nur ein Flag als booleschen Wert.

Im folgenden Beispiel ist die Option autoId eine Flag-Option, die keine Daten an die Funktion übergibt, so dass wir sie wie cli create collection -c c_name -p p_name -a verwenden können.

@createDetails.command('collection')
@click.option('-c', '--collection-name', 'collectionName', help='Collection name to be created.', default='')
@click.option('-p', '--schema-primary-field', 'primaryField', help='Primary field name.', default='')
@click.option('-a', '--schema-auto-id', 'autoId', help='Enable auto id.', default=False, is_flag=True)
@click.pass_obj
def createCollection(obj, collectionName, primaryField, autoId, description, fields):
    pass

Argumente hinzufügen

In diesem Projekt ersetzen wir die Verwendung von Argumenten durch die Verwendung von Optionen. Aber wir führen hier trotzdem die Verwendung von Argumenten ein. Im Gegensatz zu Optionen werden Argumente wie cli COMMAND [OPTIONS] ARGUEMENTS verwendet. Wenn wir das obige Beispiel in die Verwendung von arguements umwandeln, sieht es so aus:

@createDetails.command('collection')
@click.argument('collectionName')
@click.option('-p', '--schema-primary-field', 'primaryField', help='Primary field name.', default='')
@click.option('-a', '--schema-auto-id', 'autoId', help='Enable auto id.', default=False, is_flag=True)
@click.pass_obj
def createCollection(obj, collectionName, primaryField, autoId, description, fields):
    pass

Dann sollte die Verwendung cli create collection c_name -p p_name -a sein.

Vollständige Hilfemeldung hinzufügen

So wie wir die kurze Hilfemeldung oben definiert haben, können wir die vollständige Hilfemeldung in der Funktion definieren:

@cli.command(no_args_is_help=False)
@click.option('-a', '--alias', 'alias', help="Milvus link alias name, default is `default`.", default='default', type=str)
@click.option('-h', '--host', 'host', help="Host name, default is `127.0.0.1`.", default='127.0.0.1', type=str)
@click.option('-p', '--port', 'port', help="Port, default is `19530`.", default=19530, type=int)
@click.pass_obj
def connect(obj, alias, host, port):
    """
    Connect to Milvus.

    Example:

        milvus_cli > connect -h 127.0.0.1 -p 19530 -a default
    """
    try:
        obj.connect(alias, host, port)
    except Exception as e:
        click.echo(message=e, err=True)
    else:
        click.echo("Connect Milvus successfully!")
        click.echo(obj.showConnection(alias))

Der erste Block innerhalb der Funktion ist die Hilfemeldung, die nach der Eingabe von cli connect --help ausgegeben wird.

milvus_cli > connect --help
Usage: milvus_cli.py connect [OPTIONS]

  Connect to Milvus.

  Example:

      milvus_cli > connect -h 127.0.0.1 -p 19530 -a default

Options:
  -a, --alias TEXT    Milvus link alias name, default is `default`.
  -h, --host TEXT     Host name, default is `127.0.0.1`.
  -p, --port INTEGER  Port, default is `19530`.
  --help              Show this message and exit.

Bestätigung hinzufügen

Manchmal muss der Benutzer eine Aktion bestätigen, insbesondere wenn er etwas löschen möchte. Wir können click.confirm hinzufügen, um eine Pause einzulegen und den Benutzer um eine Bestätigung zu bitten:

@deleteSth.command('collection')
@click.option('-c', '--collection', 'collectionName', help='The name of collection to be deleted.', default='')
@click.option('-t', '--timeout', 'timeout', help='An optional duration of time in seconds to allow for the RPC. If timeout is set to None, the client keeps waiting until the server responds or an error occurs.', default=None, type=int)
@click.pass_obj
def deleteCollection(obj, collectionName, timeout):
    """
    Drops the collection together with its index files.

    Example:

        milvus_cli > delete collection -c car
    """
    click.echo(
        "Warning!\nYou are trying to delete the collection with data. This action cannot be undone!\n")
    if not click.confirm('Do you want to continue?'):
        return
    pass

Wie im obigen Beispiel wird eine Bestätigungskonversation wie Aborted!ant to continue? [y/N]: angezeigt.

Prompts hinzufügen

Um Prompts zu implementieren, müssen wir nur click.prompt hinzufügen.

@cli.command()
@click.pass_obj
def query(obj):
    """
    Query with a set of criteria, and results in a list of records that match the query exactly.
    """
    collectionName = click.prompt(
        'Collection name', type=click.Choice(obj._list_collection_names()))
    expr = click.prompt('The query expression(field_name in [x,y])')
    partitionNames = click.prompt(
        f'The names of partitions to search(split by "," if multiple) {obj._list_partition_names(collectionName)}', default='')
    outputFields = click.prompt(
        f'Fields to return(split by "," if multiple) {obj._list_field_names(collectionName)}', default='')
    timeout = click.prompt('timeout', default='')
    pass

Die Aufforderung wird bei jedem click.prompt angezeigt. Wir verwenden mehrere Eingabeaufforderungen hintereinander, damit es wie eine kontinuierliche Konversation aussieht. Dadurch wird sichergestellt, dass der Benutzer die Daten in der gewünschten Reihenfolge eingibt. In diesem Fall muss der Benutzer zuerst eine Sammlung auswählen, und wir müssen alle Partitionen unter dieser Sammlung abrufen, um sie dann dem Benutzer zur Auswahl zu zeigen.

Auswahlmöglichkeiten hinzufügen

Manchmal möchten Sie, dass der Benutzer nur einen begrenzten Bereich/Typ von Werten eingibt, dann können Sie type=click.Choice([<any>]) zu click.prompt, click.options und etc. hinzufügen.

Zum Beispiel,

collectionName = click.prompt(
        'Collection name', type=click.Choice(['collection_1', 'collection_2']))

Dann kann der Benutzer nur collection_1 oder collection_2 eingeben, bei anderen Eingaben wird ein Fehler ausgelöst.

Clear Screen hinzufügen

Sie können click.clear() verwenden, um dies zu implementieren.

@cli.command()
def clear():
    """Clear screen."""
    click.clear()

Zusätzliche Tipps

  • Der Standardwert ist None, daher ist es bedeutungslos, wenn Sie den Standardwert als None angeben. Und der Standardwert None führt dazu, dass click.prompt ständig angezeigt wird, wenn Sie einen Wert leer lassen wollen, um ihn zu überspringen.

Implementierung einer CLI-Eingabeaufforderung für den Benutzer

Warum Prompt CLI

Für den Datenbankbetrieb benötigen wir eine ständige Verbindung zu einer Instanz. Wenn wir den ursprünglichen Befehlszeilenmodus verwenden, wird die Verbindung nach jedem ausgeführten Befehl getrennt. Wir wollen auch einige Daten speichern, wenn wir CLI verwenden, und sie nach dem Beenden löschen.

Implementieren Sie

  1. Verwenden Sie while True, um kontinuierlich die Eingaben des Benutzers abzuhören.
def runCliPrompt():
    while True:
        astr = input('milvus_cli > ')
        try:
            cli(astr.split())
        except SystemExit:
            # trap argparse error message
            # print('error', SystemExit)
            continue


if __name__ == '__main__':
    runCliPrompt()
  1. Die Verwendung von input bewirkt, dass up, down, left, right Pfeiltasten, tab und einige andere Tasten automatisch in Acsii-Strings umgewandelt werden. Außerdem können History-Befehle nicht aus der Sitzung gelesen werden. Also fügen wir readline in die Funktion runCliPrompt ein.
def runCliPrompt():
    while True:
            import readline
        readline.set_completer_delims(' \t\n;')
        astr = input('milvus_cli > ')
        try:
            cli(astr.split())
        except SystemExit:
            # trap argparse error message
            # print('error', SystemExit)
            continue
  1. quit CLI hinzufügen.
@cli.command('exit')
def quitapp():
    """Exit the CLI."""
    global quitapp
    quitapp = True


quitapp = False  # global flag


def runCliPrompt():
    while not quitapp:
            import readline
        readline.set_completer_delims(' \t\n;')
        astr = input('milvus_cli > ')
        try:
            cli(astr.split())
        except SystemExit:
            # trap argparse error message
            # print('error', SystemExit)
            continue
  1. Abfangen des KeyboardInterrupt Fehlers, wenn ctrl C zum Beenden verwendet wird.
def runCliPrompt():
    try:
        while not quitapp:
            import readline
            readline.set_completer_delims(' \t\n;')
            astr = input('milvus_cli > ')
            try:
                cli(astr.split())
            except SystemExit:
                # trap argparse error message
                # print('error', SystemExit)
                continue
    except KeyboardInterrupt:
        sys.exit(0)
  1. Nachdem alles erledigt ist, sieht die CLI nun so aus:
milvus_cli >
milvus_cli > connect
+-------+-----------+
| Host  | 127.0.0.1 |
| Port  |   19530   |
| Alias |  default  |
+-------+-----------+

milvus_cli > help
Usage:  [OPTIONS] COMMAND [ARGS]...

  Milvus CLI

Commands:
  clear     Clear screen.
  connect   Connect to Milvus.
  create    Create collection, partition and index.
  delete    Delete specified collection, partition and index.
  describe  Describe collection or partition.
  exit      Exit the CLI.
  help      Show help messages.
  import    Import data from csv file with headers and insert into target...
  list      List collections, partitions and indexes.
  load      Load specified collection.
  query     Query with a set of criteria, and results in a list of...
  release   Release specified collection.
  search    Conducts a vector similarity search with an optional boolean...
  show      Show connection, loading_progress and index_progress.
  version   Get Milvus CLI version.

milvus_cli > exit

Manuelles Implementieren von Autocomplete

Anders als die Shell-Autovervollständigung von Click umschließt unser Projekt die Befehlszeile und verwendet eine Schleife, um die Benutzereingabe zu erhalten und eine Befehlszeile zu implementieren. Wir müssen also einen Vervollständiger an readline binden.

class Completer(object):
    RE_SPACE = re.compile('.*\s+$', re.M)
    CMDS_DICT = {
        'clear': [],
        'connect': [],
        'create': ['collection', 'partition', 'index'],
        'delete': ['collection', 'partition', 'index'],
        'describe': ['collection', 'partition'],
        'exit': [],
        'help': [],
        'import': [],
        'list': ['collections', 'partitions', 'indexes'],
        'load': [],
        'query': [],
        'release': [],
        'search': [],
        'show': ['connection', 'index_progress', 'loading_progress'],
        'version': [],
    }

    def __init__(self) -> None:
        super().__init__()
        self.COMMANDS = list(self.CMDS_DICT.keys())
        self.createCompleteFuncs(self.CMDS_DICT)

    def createCompleteFuncs(self, cmdDict):
        for cmd in cmdDict:
            sub_cmds = cmdDict[cmd]
            complete_example = self.makeComplete(cmd, sub_cmds)
            setattr(self, 'complete_%s' % cmd, complete_example)

    def makeComplete(self, cmd, sub_cmds):
        def f_complete(args):
            f"Completions for the {cmd} command."
            if not args:
                return self._complete_path('.')
            if len(args) <= 1 and not cmd == 'import':
                return self._complete_2nd_level(sub_cmds, args[-1])
            return self._complete_path(args[-1])
        return f_complete

    def _listdir(self, root):
        "List directory 'root' appending the path separator to subdirs."
        res = []
        for name in os.listdir(root):
            path = os.path.join(root, name)
            if os.path.isdir(path):
                name += os.sep
            res.append(name)
        return res

    def _complete_path(self, path=None):
        "Perform completion of filesystem path."
        if not path:
            return self._listdir('.')
        dirname, rest = os.path.split(path)
        tmp = dirname if dirname else '.'
        res = [os.path.join(dirname, p)
               for p in self._listdir(tmp) if p.startswith(rest)]
        # more than one match, or single match which does not exist (typo)
        if len(res) > 1 or not os.path.exists(path):
            return res
        # resolved to a single directory, so return list of files below it
        if os.path.isdir(path):
            return [os.path.join(path, p) for p in self._listdir(path)]
        # exact file match terminates this completion
        return [path + ' ']

    def _complete_2nd_level(self, SUB_COMMANDS=[], cmd=None):
        if not cmd:
            return [c + ' ' for c in SUB_COMMANDS]
        res = [c for c in SUB_COMMANDS if c.startswith(cmd)]
        if len(res) > 1 or not (cmd in SUB_COMMANDS):
            return res
        return [cmd + ' ']

    def complete(self, text, state):
        "Generic readline completion entry point."
        buffer = readline.get_line_buffer()
        line = readline.get_line_buffer().split()
        # show all commands
        if not line:
            return [c + ' ' for c in self.COMMANDS][state]
        # account for last argument ending in a space
        if self.RE_SPACE.match(buffer):
            line.append('')
        # resolve command to the implementation function
        cmd = line[0].strip()
        if cmd in self.COMMANDS:
            impl = getattr(self, 'complete_%s' % cmd)
            args = line[1:]
            if args:
                return (impl(args) + [None])[state]
            return [cmd + ' '][state]
        results = [
            c + ' ' for c in self.COMMANDS if c.startswith(cmd)] + [None]
        return results[state]

Nachdem wir Completer definiert haben, können wir es mit readline verbinden:

comp = Completer()


def runCliPrompt():
    try:
        while not quitapp:
            import readline
            readline.set_completer_delims(' \t\n;')
            readline.parse_and_bind("tab: complete")
            readline.set_completer(comp.complete)
            astr = input('milvus_cli > ')
            try:
                cli(astr.split())
            except SystemExit:
                # trap argparse error message
                # print('error', SystemExit)
                continue
    except KeyboardInterrupt:
        sys.exit(0)

Einmalige Option hinzufügen

Für die Eingabeaufforderung in der Kommandozeile wollen wir manchmal nicht vollständig in die Skripte einsteigen, um einige Informationen wie die Version zu erhalten. Ein gutes Beispiel ist Python, wenn Sie python im Terminal eingeben, wird die Promtp-Befehlszeile angezeigt, aber es wird nur eine Versionsmeldung zurückgegeben und die Prompt-Skripte werden nicht aufgerufen, wenn Sie python -V eingeben. Wir können also sys.args in unserem Code verwenden.

def runCliPrompt():
    args = sys.argv
    if args and (args[-1] == '--version'):
        print(f"Milvus Cli v{getPackageVersion()}")
        return
    try:
        while not quitapp:
            import readline
            readline.set_completer_delims(' \t\n;')
            readline.parse_and_bind("tab: complete")
            readline.set_completer(comp.complete)
            astr = input('milvus_cli > ')
            try:
                cli(astr.split())
            except SystemExit:
                # trap argparse error message
                # print('error', SystemExit)
                continue
    except KeyboardInterrupt:
        sys.exit(0)


if __name__ == '__main__':
    runCliPrompt()

Wir erhalten sys.args vor der Schleife, wenn wir die CLI-Skripte zum ersten Mal aufrufen. Wenn das letzte Argument --version ist, wird der Code die Paketversion zurückgeben, ohne in die Schleife zu laufen.

Dies wird hilfreich sein, nachdem wir den Code als Paket erstellt haben. Der Benutzer kann milvus_cli eingeben, um eine CLI-Eingabeaufforderung zu erhalten, oder milvus_cli --version, um nur die Version zu erhalten.

Bauen und freigeben

Schließlich wollen wir ein Paket erstellen und mit PYPI freigeben. Damit der Benutzer einfach pip install <package name> zur Installation verwenden kann.

Zu Testzwecken lokal installieren

Bevor Sie das Paket in PYPI veröffentlichen, möchten Sie es vielleicht für einige Tests lokal installieren.

In diesem Fall können Sie einfach cd in das Paketverzeichnis kopieren und pip install -e . ausführen (vergessen Sie nicht .).

Paketdateien erstellen

Siehe: https://packaging.python.org/tutorials/packaging-projects/

Die Struktur eines Pakets sollte wie folgt aussehen:

package_example/
├── LICENSE
├── README.md
├── setup.py
├── src/
│   ├── __init__.py
│   ├── main.py
│   └── scripts/
│       ├── __init__.py
│       └── example.py
└── tests/

Erstellen Sie das Paketverzeichnis

Erstellen Sie das Verzeichnis Milvus_cli mit der folgenden Struktur:

Milvus_cli/
├── LICENSE
├── README.md
├── setup.py
├── milvus_cli/
│   ├── __init__.py
│   ├── main.py
│   ├── utils.py
│   └── scripts/
│       ├── __init__.py
│       └── milvus_cli.py
└── dist/

Schreiben Sie den Eintragscode

Der Eintrag für das Skript sollte sich in Milvus_cli/milvus_cli/scripts befinden, und die Milvus_cli/milvus_cli/scripts/milvus_cli.py sollte wie folgt aussehen:

import sys
import os
import click
from utils import PyOrm, Completer


pass_context = click.make_pass_decorator(PyOrm, ensure=True)


@click.group(no_args_is_help=False, add_help_option=False, invoke_without_command=True)
@click.pass_context
def cli(ctx):
    """Milvus CLI"""
    ctx.obj = PyOrm()

"""
...
Here your code.
...
"""

@cli.command('exit')
def quitapp():
    """Exit the CLI."""
    global quitapp
    quitapp = True


quitapp = False  # global flag
comp = Completer()


def runCliPrompt():
    args = sys.argv
    if args and (args[-1] == '--version'):
        print(f"Milvus Cli v{getPackageVersion()}")
        return
    try:
        while not quitapp:
            import readline
            readline.set_completer_delims(' \t\n;')
            readline.parse_and_bind("tab: complete")
            readline.set_completer(comp.complete)
            astr = input('milvus_cli > ')
            try:
                cli(astr.split())
            except SystemExit:
                # trap argparse error message
                # print('error', SystemExit)
                continue
            except Exception as e:
                click.echo(
                    message=f"Error occurred!\n{str(e)}", err=True)
    except KeyboardInterrupt:
        sys.exit(0)


if __name__ == '__main__':
    runCliPrompt()

Bearbeiten Sie die setup.py

from setuptools import setup, find_packages

with open("README.md", "r", encoding="utf-8") as fh:
    long_description = fh.read()

setup(
    name='milvus_cli',
    version='0.1.6',
    author='Milvus Team',
    author_email='milvus-team@zilliz.com',
    url='https://github.com/milvus-io/milvus_cli',
    description='CLI for Milvus',
    long_description=long_description,
    long_description_content_type='text/markdown',
    license='Apache-2.0',
    packages=find_packages(),
    include_package_data=True,
    install_requires=[
        'Click==8.0.1',
        'pymilvus==2.0.0rc5',
        'tabulate==0.8.9'
    ],
    entry_points={
        'console_scripts': [
            'milvus_cli = milvus_cli.scripts.milvus_cli:runCliPrompt',
        ],
    },
    python_requires='>=3.8'
)

Hier einige Tipps:

  1. Wir verwenden den Inhalt von README.md als die lange Beschreibung des Pakets.
  2. Fügen Sie alle Abhängigkeiten zu install_requires hinzu.
  3. Geben Sie entry_points an. In diesem Fall setzen wir milvus_cli als ein Kind von console_scripts, so dass wir milvus_cli direkt nach der Installation dieses Pakets als Befehl eingeben können. Und der Einstiegspunkt von milvus_cli ist die Funktion runCliPrompt in milvus_cli/scripts/milvus_cli.py.

Erstellen Sie

  1. Aktualisieren Sie das Paket build: python3 -m pip install --upgrade build

  2. Führen Sie build aus: python -m build --sdist --wheel --outdir dist/ .

  3. Es werden zwei Dateien im Verzeichnis dist/ erzeugt:

dist/
  example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
  example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz

Freigabe veröffentlichen

Siehe: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives

  1. Aktualisieren Sie das twine -Paket: python3 -m pip install --upgrade twine
  2. Hochladen auf PYPI test env: python3 -m twine upload --repository testpypi dist/*
  3. Hochladen auf PYPI: python3 -m twine upload dist/*

CI/CD durch Github-Workflows

Verweis auf: https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/

Wir wollen einen Weg, um Vermögenswerte automatisch hochladen, kann es die Pakete bauen und laden Sie sie auf Github Releases und PYPI.

(Aus irgendeinem Grund wollen wir nur, dass der Workflow nur die Freigabe zum Testen von PYPI veröffentlicht).

# This is a basic workflow to help you get started with Actions

name: Update the release's assets after it published

# Controls when the workflow will run
on:
  release:
    # The workflow will run after release published
    types: [published]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: '3.8'
          architecture: 'x64'
      - name: Install pypa/build
        run: >-
          python -m
          pip install
          build
          --user
      - name: Clean dist/
        run: |
          sudo rm -fr dist/*
      - name: Build a binary wheel and a source tarball
        run: >-
          python -m
          build
          --sdist
          --wheel
          --outdir dist/
          .
      # Update target github release's assets
      - name: Update assets
        uses: softprops/action-gh-release@v1
        if: startsWith(github.ref, 'refs/tags/')
        with:
          files: ./dist/*
      - name: Publish distribution 📦 to Test PyPI
        if: contains(github.ref, 'beta') && startsWith(github.ref, 'refs/tags')
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.TEST_PYPI_API_TOKEN }}
          repository_url: https://test.pypi.org/legacy/
          packages_dir: dist/
          verify_metadata: false

Erfahren Sie mehr über Milvus

Milvus ist ein leistungsfähiges Tool, das eine Vielzahl von Anwendungen für künstliche Intelligenz und Vektorähnlichkeitssuche unterstützt. Um mehr über das Projekt zu erfahren, lesen Sie die folgenden Ressourcen:

  • Lesen Sie unseren Blog.
  • Interagieren Sie mit unserer Open-Source-Community auf Slack.
  • Nutzen Sie die beliebteste Vektordatenbank der Welt auf GitHub oder tragen Sie zu ihr bei.
  • Testen und implementieren Sie KI-Anwendungen schnell mit unserem neuen Bootcamp.

Like the article? Spread the word

Weiterlesen