Files
semantic-kernel/python/DEV_SETUP.md
T
Julio Carlos MenendezandEvan Mattson d97f9536c4 Python: Removes the _async suffix where is not needed (#4735)
### Motivation and Context
Delete all *_async where *_sync doesn't exist to make the library more
Pythonic.

Fixes #4629 

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [X] The code builds clean without any errors or warnings
- [X] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [X] All unit tests pass, and I have added new tests where possible
- [X] I didn't break anyone 😄

---------

Co-authored-by: Evan Mattson <[email protected]>
2024-01-26 17:15:35 +00:00

289 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dev Setup
This document describes how to setup your environment with Python and Poetry,
if you're working on new features or a bug fix for Semantic Kernel, or simply
want to run the tests included.
## LLM setup
Make sure you have an
[OpenAI API Key](https://openai.com/product/) or
[Azure OpenAI service key](https://learn.microsoft.com/azure/cognitive-services/openai/quickstart?pivots=rest-api)
Copy those keys into a `.env` file (see the `.env.example` file):
```bash
OPENAI_API_KEY=""
OPENAI_ORG_ID=""
AZURE_OPENAI_DEPLOYMENT_NAME=""
AZURE_OPENAI_ENDPOINT=""
AZURE_OPENAI_API_KEY=""
```
We suggest adding a copy of the `.env` file under these folders:
- [python/tests](tests)
- [./notebooks](./notebooks).
## System setup
To get started, you'll need VSCode and a local installation of Python 3.8+.
You can run:
```python
python3 --version ; pip3 --version ; code -v
```
to verify that you have the required dependencies.
## If you're on WSL
Check that you've cloned the repository to `~/workspace` or a similar folder.
Avoid `/mnt/c/` and prefer using your WSL user's home directory.
Ensure you have the WSL extension for VSCode installed (and the Python extension
for VSCode installed).
You'll also need `pip3` installed. If you don't yet have a `python3` install in WSL,
you can run:
```bash
sudo apt-get update && sudo apt-get install python3 python3-pip
```
ℹ️ **Note**: if you don't have your PATH setup to find executables installed by `pip3`,
you may need to run `~/.local/bin/poetry install` and `~/.local/bin/poetry shell`
instead. You can fix this by adding `export PATH="$HOME/.local/bin:$PATH"` to
your `~/.bashrc` and closing/re-opening the terminal.\_
## Using Poetry
Poetry allows to use SK from the local files, without worrying about paths, as
if you had SK pip package installed.
To install Poetry in your system, first, navigate to the directory containing
this README using your chosen shell. You will need to have Python 3.8+ installed.
Install the Poetry package manager and create a project virtual environment.
Note: SK requires at least Poetry 1.2.0.
```bash
# Install poetry package
pip3 install poetry
# Use poetry to install base project dependencies
poetry install
# If you want to use connectors such as hugging face
# poetry install --with <connector group name>
# example: poetry install --with hugging_face
# Use poetry to activate project venv
poetry shell
```
## VSCode Setup
Open any of the `.py` files in the project and run the `Python: Select Interpreter`
command from the command palette. Make sure the virtual env (venv) created by
`poetry` is selected.
The python you're looking for should be under `~/.cache/pypoetry/virtualenvs/semantic-kernel-.../bin/python`.
If prompted, install `black` and `flake8` (if VSCode doesn't find those packages,
it will prompt you to install them).
## Tests
You can run the unit tests under the [tests/unit](tests/unit/) folder.
```bash
cd python
poetry install
poetry run pytest tests/unit
```
You can run the integration tests under the [tests/integration](tests/integration/) folder.
```bash
cd python
poetry install
poetry run pytest tests/integration
```
You can also run all the tests together under the [tests](tests/) folder.
```bash
cd python
poetry install
poetry run pytest tests
```
## Tools and scripts
## Implementation Decisions
### Asynchronous programming
It's important to note that most of this library is written with asynchronous in mind. The
developer should always assume everything is asynchronous. One can use the function signature
with either `async def` or `def` to understand if something is asynchronous or not.
## Pydantic and Serialization
[Pydantic Documentation](https://docs.pydantic.dev/1.10/)
### Overview
This section describes how one can enable serialization for their class using Pydantic.
IMPORTANT: This document (and SemanticKernel) currently use Pydantic 1.x. When SK is upgraded
to use Pydantic 2.x, this document will be upgraded accordingly.
### Terminology
There are 3 types of classes you need to be aware of when enabling serialization with Pydantic:
1. Classes which contain no data - examples are Protocols, ABC subclasses and any other classes
that don't contain any data that needs to be serialized.
2. Classes which contain data that need to be serialized, but don't contain any generic classes.
3. Classes which contain data that need to be serialized, AND contain generic classes.
### Upgrading existing classes to use Pydantic
#### Classes without any data
Let's take the following classes as examples - 1 ABC, 1 Protocol, and 1 class that only contains
data that doesn't need to be serialized.
```python
class A(Protocol):
def some_method(self, *args, **kwargs): ...
class B(ABC):
def some_method(self, *args, **kwargs): ...
class C:
def __init__(self):
# IMPORTANT: These variables are NOT being passed into the initializer
# so they don't need to be serialized. If the are though, you'll have
# to treat this as a class that contains data that needs to be serialized
self._a = ...
```
For `Protocol` subclasses, nothing needs to be done, and they can be left as is.
For the remaining types, SemanticKernel provides a class named `PydanticField`. Subclassing
from this field is sufficient to have these types of classes as valid Pydantic fields, and allows
any class using them as attributes to be serialized.
```python
from semantic_kernel.kernel_pydantic import PydanticField
class B(PydanticField): ... # correct, B is still an ABC because PydanticField subclasses ABC
class B(PydanticField, ABC): ... # Also correct
class B(ABC, PydanticField): ... # ERROR: Python cannot find a valid super class ordering.
class C(PydanticField): ... # No other changes needed
```
The classes B and C can now be used as valid Pydantic Field annotations.
```python
from pydantic import BaseModel
class MyModel(BaseModel):
b: B
c: C
```
Class A can only be used as a Pydantic Field annotation for a Pydantic BaseModel subclass
which is configured to allow arbitrary field types like so:
```python
from pydantic import BaseModel
class IncorrectModel(BaseModel):
a: A # Pydantic error
class CorrectModel(BaseModel):
a: A # Okay
class Config: # Configuration that tells Pydantic to allow field types that it can't serialize
arbitrary_types_allowed = True
```
#### Classes with data, but no Generic types that need to be serialized
If your class has any data that needs to be serialized, but the field annotation for that data type
in your class is not a Generic type, this section applies to you.
Let's take the following example:
```python
class A:
def __init__(self, a: int, b: float, c: List[float], d: dict[str, tuple[float, str]] = {}):
# Since a, b, c and d are needed to initialize this class, they need to be serialized
# if can be serialized.
# Although a, b, c and d are builtin python types, any valid pydantic field can be used
# here. This includes the classes defined in the previous category.
self.a = a
self.b = b
self.c = c
self.d = d
```
You would convert this to a Pydantic class by subclassing from the `KernelBaseModel` class.
```python
from pydantic import Field
from semantic_kernel.kernel_pydantic import KernelBaseModel
class A(KernelBaseModel):
# The notation for the fields is similar to dataclasses.
a: int
b: float
c: List[float]
# Only, instead of using dataclasses.field, you would use pydantic.Field
d: dict[str, tuple[flost, str]] = Field(default_factory=dict)
```
#### Classes with data that need to be serialized, and some of them are Generic types
Let's take the following example:
```python
from typing import TypeVar
T1 = TypeVar("T1")
T2 = TypeVar("T2", bound=<some class>)
class A:
def __init__(a: int, b: T1, c: T2):
self.a = a
self.b = b
self.c = c
```
You can use the `KernelBaseModel` to convert these to pydantic serializable classes.
```python
from typing import Generic
from semantic_kernel.kernel_pydantic import KernelBaseModel
class A(KernelBaseModel, Generic[T1, T2]):
# T1 and T2 must be specified in the Generic argument otherwise, pydantic will
# NOT be able to serialize this class
a: int
b: T1
c: T2
```
## Pipeline checks
To run the same checks that run during the GitHub Action build, you can use
this command, from the [python](../python) folder:
```bash
poetry run pre-commit run -c .conf/.pre-commit-config.yaml -a
```