🚀 Prova Zilliz Cloud, la versione completamente gestita di Milvus, gratuitamente—sperimenta prestazioni 10 volte più veloci! Prova Ora>>

milvus-logo
LFAI

Panoramica

  • Engineering
September 15, 2021
Zhen Chen

Panoramica

URL del progetto: https://github.com/milvus-io/milvus_cli

Preparazione: Python3.8, Click 8.0.x

Raggruppare i comandi

Creare un comando

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()

Come nel codice precedente, usiamo @click.group() per creare un gruppo di comandi cli come punto di ingresso. Per implementare un prompt CLI dobbiamo disabilitare i messaggi di aiuto per la voce, quindi aggiungiamo no_args_is_help=False, add_help_option=False e invoke_without_command=True. Non verrà stampato nulla se si inserisce cli solo nel terminale.

Inoltre usiamo @click.pass_context per passare un contesto a questo gruppo per un ulteriore utilizzo.

Creare un sottocomando del gruppo di comandi

Aggiungiamo il primo sottocomando help sotto cli:

# 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))

Ora possiamo usare cli help nel terminale:

$ python milvus_cli/scripts/milvus_cli.py help

Creare un sottogruppo di un gruppo di comandi

Non solo vogliamo avere un sottocomando come cli help, ma abbiamo anche bisogno di un sottogruppo di comandi come cli list collection, cli list partition e cli list indexes.

Per prima cosa creiamo un sottogruppo di comandi list, in questo caso possiamo passare il primo parametro a @cli.group come nome del comando invece di usare il nome della funzione predefinita, in modo da ridurre i nomi di funzione duplicati.

Attenzione, qui usiamo @cli.group() invece di @click.group in modo da creare un sottogruppo del gruppo di origine.

Utilizziamo @click.pass_obj per passare context.obj ai comandi secondari di questo sottogruppo.

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

Poi aggiungiamo alcuni comandi secondari a questo sottogruppo tramite @listDetails.command() (non @cli.command()). Questo è solo un esempio, si può ignorare l'implementazione e se ne parlerà in seguito.

@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)

Dopo aver completato tutte queste operazioni, abbiamo un gruppo di comandi che ha l'aspetto di un miltigruppo:

image immagine

Personalizzare un comando

Aggiungere opzioni

È possibile aggiungere alcune opzioni a un comando che verrà utilizzato come cli --test-option value.

Ecco un esempio: aggiungiamo tre opzioni alias, host e port per specificare un indirizzo da collegare a Milvus.

I primi due parametri definiscono il nome breve e completo dell'opzione, il terzo parametro definisce il nome della variabile, il parametro help specifica il breve messaggio di aiuto, il parametro default specifica il valore predefinito e type specifica il tipo di valore.

Tutti i valori delle opzioni saranno passati alla funzione in ordine di definizione.

@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

Aggiungere opzioni di flag

Abbiamo usato le opzioni per passare un valore, ma a volte abbiamo bisogno di un flag come valore booleano.

Come nell'esempio seguente, l'opzione autoId è un'opzione flag e non passa alcun dato alla funzione, quindi possiamo usarla come cli create collection -c c_name -p p_name -a.

@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

Aggiungere argomenti

In questo progetto sostituiamo l'uso degli argomenti con quello delle opzioni. Ma qui introduciamo comunque l'uso degli argomenti. A differenza delle opzioni, gli argomenti sono usati come cli COMMAND [OPTIONS] ARGUEMENTS. Se convertiamo l'esempio precedente nell'uso degli argomenti, sarà così:

@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

Allora l'uso dovrebbe essere cli create collection c_name -p p_name -a.

Aggiungere un messaggio di aiuto completo

Come abbiamo definito il messaggio di aiuto breve sopra, possiamo definire il messaggio di aiuto completo nella funzione:

@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))

Il primo blocco all'interno della funzione è il messaggio di aiuto che verrà stampato dopo aver inserito cli connect --help.

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.

Aggiungere la conferma

A volte è necessario che l'utente confermi un'azione, in particolare la cancellazione di qualcosa. Possiamo aggiungere click.confirm per mettere in pausa e chiedere all'utente di confermare:

@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

Come nell'esempio precedente, una conversazione di conferma verrà visualizzata come Aborted!ant to continue? [y/N]:.

Aggiungere i prompt

Per implementare i prompt è sufficiente aggiungere click.prompt.

@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

Il prompt verrà visualizzato a ogni click.prompt. Utilizziamo alcuni prompt in serie, in modo che sembri una conversazione continua. Questo assicura che l'utente inserisca i dati nell'ordine desiderato. In questo caso è necessario che l'utente scelga prima una collezione e che ottenga tutte le partizioni sotto questa collezione, mostrandole poi all'utente per la scelta.

Aggiungere scelte

A volte si vuole che l'utente inserisca solo una gamma limitata di valori, per cui si può aggiungere type=click.Choice([<any>]) a click.prompt, click.options e così via.

Ad esempio,

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

L'utente può inserire solo collection_1 o collection_2, mentre in caso di altri input verrà generato un errore.

Aggiunta di una schermata chiara

È possibile utilizzare click.clear() per implementarlo.

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

Suggerimenti aggiuntivi

  • Il valore predefinito è None, quindi non ha senso se si specifica il valore predefinito come None. Il valore predefinito None causerà la visualizzazione continua di click.prompt, se si vuole lasciare un valore vuoto per saltarlo.

Implementare il prompt CLI per l'inserimento da parte dell'utente

Perché prompt CLI

Per il funzionamento del database, abbiamo bisogno di una connessione continua a un'istanza. Se utilizziamo la modalità origin command line, la connessione verrà interrotta dopo ogni comando eseguito. Vogliamo anche memorizzare alcuni dati durante l'uso della CLI e pulirli dopo l'uscita.

Implementare

  1. Utilizzare while True per ascoltare continuamente l'input dell'utente.
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. Utilizzando solo input, i tasti freccia up, down, left, right, il tasto tab e alcuni altri tasti verranno convertiti automaticamente in stringhe Acsii. Inoltre, i comandi della cronologia non possono essere letti dalla sessione. Quindi aggiungiamo readline alla funzione runCliPrompt.
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. Aggiungere quit CLI.
@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. Cogliere l'errore di KeyboardInterrupt quando si usa ctrl C per uscire.
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. Dopo aver sistemato tutto, la CLI si presenta come segue:
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

Implementare manualmente il completamento automatico

A differenza del completamento automatico della shell di click, il nostro progetto avvolge la riga di comando e usa un ciclo per ottenere l'input dell'utente e implementare una riga di comando immediata. Per questo motivo, dobbiamo associare un completatore a readline.

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]

Dopo aver definito Completer, possiamo collegarlo a readline:

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)

Aggiungere un'opzione una tantum

Per il prompt a riga di comando, a volte non si vuole eseguire completamente lo script per ottenere alcune informazioni come la versione. Un buon esempio è Python, quando si digita python nel terminale viene visualizzata la riga di comando del prompt, ma restituisce solo un messaggio di versione e non entra negli script del prompt se si digita python -V. Possiamo quindi utilizzare sys.args nel nostro codice per implementarlo.

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()

Otteniamo sys.args prima del ciclo quando viene eseguito per la prima volta lo script CLI. Se l'ultimo argomento è --version, il codice restituirà la versione del pacchetto senza entrare nel ciclo.

Sarà utile dopo aver creato il codice come pacchetto. L'utente può digitare milvus_cli per passare a un prompt CLI, oppure milvus_cli --version per ottenere solo la versione.

Creazione e rilascio

Infine, vogliamo creare un pacchetto e rilasciarlo tramite PYPI. In questo modo l'utente può semplicemente usare pip install <package name> per installare.

Installare localmente per i test

Prima di pubblicare il pacchetto su PYPI, potreste volerlo installare localmente per alcuni test.

In questo caso, è sufficiente inserire cd nella directory del pacchetto ed eseguire pip install -e . (non dimenticate .).

Creare i file del pacchetto

Fare riferimento a: https://packaging.python.org/tutorials/packaging-projects/

La struttura di un pacchetto dovrebbe essere così:

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

Creare la directory del pacchetto

Creare la directory Milvus_cli con la struttura seguente:

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

Scrivere il codice di ingresso

La voce dello script dovrebbe trovarsi in Milvus_cli/milvus_cli/scripts, e Milvus_cli/milvus_cli/scripts/milvus_cli.py dovrebbe essere come:

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()

Modificare il file 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'
)

Alcuni suggerimenti:

  1. Usiamo il contenuto di README.md come descrizione lunga del pacchetto.
  2. Aggiungere tutte le dipendenze a install_requires.
  3. Specificare entry_points. In questo caso, impostiamo milvus_cli come figlio di console_scripts, in modo da poter digitare milvus_cli come comando direttamente dopo aver installato questo pacchetto. Il punto di ingresso di milvus_cli è la funzione runCliPrompt in milvus_cli/scripts/milvus_cli.py.

Costruire

  1. Aggiornare il pacchetto build: python3 -m pip install --upgrade build

  2. Eseguire build: python -m build --sdist --wheel --outdir dist/ .

  3. Verranno generati due file nella directory dist/:

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

Pubblicare il rilascio

Fare riferimento a: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives

  1. Aggiornare il pacchetto twine: python3 -m pip install --upgrade twine
  2. Caricare su PYPI test env: python3 -m twine upload --repository testpypi dist/*
  3. Caricare in PYPI: python3 -m twine upload dist/*

Flussi di lavoro CI/CD su Github

Fare riferimento a: https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/

Vogliamo un modo per caricare le risorse automaticamente, in grado di costruire i pacchetti e caricarli su github releases e PYPI.

(Per qualche motivo vogliamo che il flusso di lavoro pubblichi solo la release per testare PYPI).

# 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

Per saperne di più su Milvus

Milvus è un potente strumento in grado di alimentare una vasta gamma di applicazioni di intelligenza artificiale e di ricerca di similarità vettoriale. Per saperne di più sul progetto, consultate le seguenti risorse:

  • Leggete il nostro blog.
  • Interagire con la nostra comunità open-source su Slack.
  • Utilizzate o contribuite al database vettoriale più diffuso al mondo su GitHub.
  • Testate e distribuite rapidamente le applicazioni AI con il nostro nuovo bootcamp.

Like the article? Spread the word

Continua a Leggere