Prisma Client Py Versions Save

Prisma Client Python is an auto-generated and fully type-safe database client designed for ease of use

v0.7.1

1 year ago

What's Changed

Bug Fixes

Windows Support

This release adds official support for the Windows platform!

The main fix that comes with this release is a workaround for the missing error messages issue that has plagued so many.

Internal Improvements

A lot of the effort that went into this release was improving our internal testing strategies. This involved a major overhaul of our testing suite so that we can easily test multiple different database providers. This means we will be less likely to ship bugs and will be able to develop database specific features much faster!

In addition to the refactored test suite we also have new docker-based tests for ensuring compatibility with multiple platforms and environments that were previously untested. @jacobdr deserves a massive thank you for this!

Sponsors

sponsors

v0.7.0

1 year ago

Breaking Changes

Path resolution for relative SQLite databases fixed

Previously there was a mismatch between the resolution algorithm for relative SQLite paths which could cause the Client and the CLI to point to different databases.

The mismatch is caused by the CLI using the path to the Prisma Schema file as the base path whereas the Client used the current working directory as the base path.

The Client will now use the path to the Prisma Schema file as the base path for all relative SQLite paths, absolute paths are unchanged.

What's Changed

Add support for configuration through the pyproject.toml file

You can now configure Prisma Client Python using an entry in your pyproject.toml file instead of having to set environment variables, e.g.

[tool.prisma]
binary_cache_dir = '.binaries'

It should be noted that you can still use environment variables if you so desire, e.g.

PRISMA_BINARY_CACHE_DIR=".binaries"

This will also be useful as a workaround for #413 until the default behaviour is changed in the next release.

See the documentation for more information.

Fix .env files overriding environment variables

Previously any environment variables present in the .env or prisma/.env file would take precedence over the environment variables set at the system level. This behaviour was not correct as it does not match what the Prisma CLI does. This has now been changed such that any environment variables in the .env file will only be set if there is not an environment variable already present.

Add support for Python 3.11

Python 3.11 is now officially supported and tested!

It should be noted that you may encounter some deprecation warnings from the transitive dependencies we use.

Add support for generating JSON Schema for Bytes types

You can now generate JSON Schemas / OpenAPI Schemas for models that use the Bytes type.

from prisma import Base64
from pydantic import BaseModel

class MyModel(BaseModel):
    image: Base64

print(MyModel.schema_json(indent=2))
{
  "title": "MyModel",
  "type": "object",
  "properties": {
    "image": {
      "title": "Image",
      "type": "string",
      "format": "byte"
    }
  },
  "required": [
    "image"
  ]
}

Add support for using the Base64 type in custom pydantic models

You can now use the Base64 type in your own Pydantic models and benefit from all the advanced type coercion that Pydantic provides! Previously you would have to manually construct the Base64 instances yourself, now Pydantic will do that for you!

from prisma import Base64
from pydantic import BaseModel

class MyModel(BaseModel):
    image: Base64

# pass in a raw base64 encoded string and it will be transformed to a Base64 instance!
model = MyModel.parse_obj({'image': 'SGV5IHRoZXJlIGN1cmlvdXMgbWluZCA6KQ=='})
print(repr(model.image))  # Base64(b'SGV5IHRoZXJlIGN1cmlvdXMgbWluZCA6KQ==')

It should be noted that this assumes that the data you pass is a valid base64 string, it does not do any conversion or validation for you.

Add support for unregistering a client instance

You can now unregister a client instance, this can be very useful for writing tests that interface with Prisma Client Python. However, you shouldn't ever have to use this outside of a testing context as you should only be creating a single Prisma instance for each Python process unless you are supporting multi-tenancy. Thanks @leejayhsu for this!

from prisma.testing import unregister_client

unregister_client()

Access the location of the Prisma Schema file

You can now access the location of the Prisma Schema file used to generate Prisma Client Python.

from prisma import SCHEMA_PATH

print(SCHEMA_PATH)  # Path('/absolute/path/prisma/schema.prisma')

Other Changes

Contributors

Many thanks to @leejayhsu, @lewoudar, @tyteen4a03 and @nesb1 for contributing to this release!

Sponsors

A massive thank you to @prisma and @techied for their continued support! It is incredibly appreciated 💜

I'd also like to thank GitHub themselves for sponsoring me as part of Maintainer Month!

sponsors

v0.6.6

1 year ago

This release is a patch release to fix a regression, #402, introduced by the latest Pydantic release.

v0.6.5

2 years ago

What's Changed

Raw queries are now typed with LiteralString

This change is only applied when generating recursive types as mypy does not support LiteralString yet.

PEP 675 introduces a new string type, LiteralString, this type is a supertype of literal string types that allows functions to accept any arbitrary literal string type such as 'foo' or 'bar' for example.

All raw query methods, namely execute_raw, query_raw and query_first now take the LiteralString type as the query argument instead of str. This change means that any static type checker thats supports PEP 675 will report an error if you try and pass a string that cannot be defined statically, for example:

await User.prisma().query_raw(f'SELECT * FROM User WHERE id = {user_id}')

This change has been made to help prevent SQL injection attacks.

Thank you to @leejayhsu for contributing this feature!

Basic support for filtering by None values

You can now filter records to remove or include occurrences where a field is None or not. For example, the following query will return all User records with an email that is not None:

await client.user.find_many(
    where={
        'NOT': [{'email': None}]
    },
)

It should be noted that nested None checks are not supported yet, for example this is not valid:

await client.user.find_many(
    where={
        'NOT': [{'email': {'equals': None}}]
    },
)

It should also be noted that this does not change the return type and you will still have to perform not None checks to appease type checkers. e.g.

users = await client.user.find_many(
    where={
        'NOT': [{'email': None}]
    },
)
for user in users:
	assert user.email is not None
	print(user.email.split('@'))

New exception classes

There are two new exception classes, ForeignKeyViolationError and FieldNotFoundError.

The ForeignKeyViolationError is raised when a foreign key field has been provided but is not valid, for example, trying to create a post and connecting it to a non existent user:

await client.post.create(
    data={
        'title': 'My first post!',
        'published': True,
        'author_id': '<unknown user ID>',
    }
)

The FieldNotFoundError is raised when a field has been provided but is not valid in that context, for example, creating a record and setting a field that does not exist on that record:

await client.post.create(
    data={
        'title': 'foo',
        'published': True,
        'non_existent_field': 'foo',
    }
)

Added scalar relational fields in create input

The type definitions for creating records now contain the scalar relational fields as well as an alternative to the longer form for connecting relational fields, for example:

model User {
  id         String   @id @default(cuid())
  name       String
  email      String @unique
  posts      Post[]
}

model Post {
  id         String     @id @default(cuid())
  author     User?      @relation(fields: [author_id], references: [id])
  author_id  String?
}

With the above schema and an already existent User record. You can now create a new Post record and connect it to the user by directly setting the author_id field:

await Post.prisma().create(
  data={
      'author_id': '<existing user ID>',
      'title': 'My first post!',
  },
)

This is provided as an alternative to this query:

await Post.prisma().create(
    data={
        'title': 'My first post!',
        'author': {
            'connect': {
                'id': '<existing user ID>'
            }
        }
    },
)

Although the above query should be preferred as it also exposes other methods, such as creating the relational record inline or connecting based on other unique fields.

Prisma Upgrade

The internal Prisma binaries that Prisma Python makes use of have been upgraded from v3.11.1 to v3.13.0. For a full changelog see the v3.12.0 release notes and v3.13.0 release notes.

Minor Changes

  • Fixed typos / outdated commands in the documentation
  • Fixed long standing style issue with dark mode in the documentation

New Contributors

Many thanks to @q0w and @leejayhsu for their first contributions!

Sponsors

sponsors

v0.6.4

2 years ago

What's Changed

Experimental support for the Decimal type

Experimental support for the Decimal type has been added. The reason that support for this type is experimental is due to a missing internal feature in Prisma that means we cannot provide the same guarantees when working with the Decimal API as we can with the API for other types. For example, we cannot:

  • Raise an error if you attempt to pass a Decimal value with a greater precision than the database supports, leading to implicit truncation which may cause confusing errors
  • Set the precision level on the returned decimal.Decimal objects to match the database level, potentially leading to even more confusing errors.

If you need to use Decimal and are happy to work around these potential footguns then you must explicitly specify that you are aware of the limitations by setting a flag in the Prisma Schema:

generator py {
  provider                    = "prisma-client-py"
  enable_experimental_decimal = true
}

model User {
    id      String @id @default(cuid())
    balance Decimal
}

The Decimal type maps to the standard library's Decimal class. All available query operations can be found below:

from decimal import Decimal
from prisma import Prisma

prisma = Prisma()
user = await prisma.user.find_first(
    where={
        'balance': Decimal(1),
        # or
        'balance': {
            'equals': Decimal('1.23823923283'),
            'in': [Decimal('1.3'), Decimal('5.6')],
            'not_in': [Decimal(10), Decimal(20)],
            'gte': Decimal(5),
            'gt': Decimal(11),
            'lt': Decimal(4),
            'lte': Decimal(3),
            'not': Decimal('123456.28'),
        },
    },
)

Updates on the status of support for Decimal will be posted in #106.

Add triple-slash comments to generated models

You can now add comments to your Prisma Schema and have them appear in the docstring for models and fields! For example:

/// The User model
model User {
  /// The user's email address
  email String
}

Will generate a model that looks like this:

class User(BaseModel):
    """The User model"""

    email: str
    """The user's email address"""

Improved import error message if the client has not been generated

If you try to import Prisma or Client before you've run prisma generate then instead of getting an opaque error message:

>>> from prisma import Prisma
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'Prisma' from 'prisma' (/prisma/__init__.py)

you will now get an error like this:

>>> from prisma import Prisma
Traceback (most recent call last):
...
RuntimeError: The Client hasn't been generated yet, you must run `prisma generate` before you can use the client.
See https://prisma-client-py.readthedocs.io/en/stable/reference/troubleshooting/#client-has-not-been-generated-yet

The query batcher is now publicly exposed

You can now import the query batcher directly from the root package, making it much easier to type hint and providing support for an alternative API style:

from prisma import Prisma, Batch

prisma = Prisma()
async with Batch(prisma) as batcher:
    ...

def takes_batcher(batcher: Batch) -> None:
    ...

Prisma upgrade

The internal Prisma binaries that Prisma Python makes use of have been upgraded from v3.10.0 to v3.11.1. For a full changelog see the v3.11.0 release notes and v3.11.1 release notes.

Sponsors

This project is now being sponsored by @prisma and @techied. I am so incredibly grateful to both for supporting Prisma Client Python 💜

v0.6.3

2 years ago

What's Changed

This release is a patch release to fix incompatibilities between the documented MongoDB Prisma Schema and our version. In v3.10.0 Prisma made some breaking changes to MongoDB schemas, for example:

  • Replacing @default(dbgenerated()) with @default(auto())
  • Replacing @db.Array(ObjectId) with @db.ObjectId

This caused some confusion as following an official Prisma guide in their documentation resulted in an error (#326).

Bug Fixes

  • Disable raw queries for MongoDB as they are not officially supported yet (#324)

v0.6.2

2 years ago

Bug Fixes

In v0.6.0 we renamed Prisma to Client, in doing so we accidentally removed the export for the previous Client name which was kept for backwards compatibility. This release re-exports it so the following code will no longer raise an error:

from prisma import Client

What's Changed

Support for filtering by in and not_in for Bytes fields

For example the following query will find the first record where binary_data is either my binary data or my other binary data.

from prisma import Base64
from prisma.models import Data

await Data.prisma().find_first(
    where={
        'binary_data': {
            'in': [
                Base64.encode(b'my binary data'),
                Base64.encode(b'my other binary data'),
            ],
        },
    },
)

And if you want to find a record that doesn't match any of the arguments you can use not_in

from prisma import Base64
from prisma.models import Data

await Data.prisma().find_first(
    where={
        'binary_data': {
            'not_in': [
                Base64.encode(b'my binary data'),
                Base64.encode(b'my other binary data'),
            ],
        },
    },
)

Added __slots__ definitions

All applicable classes now define the __slots__ attribute for improved performance and memory usage, for more information on what this means, see the Python documentation.

New Contributors

Thank you to @matyasrichter 💜

v0.6.1

2 years ago

What's Changed

Support for removing all auto-generated files

Although very rare, it is sometimes possible to get your Prisma Client Python installation into a corrupted state when upgrading to a newer version. In this situation you could try uninstalling and reinstalling Prisma Client Python however doing so will not always fix the client state, in this case you have to remove all of the files that are auto-generated by Prisma Client Python. To achieve this you would either have to manually remove them or download and run a script that we use internally.

With this release you can now automatically remove all auto-generated files by running the following command:

python -m prisma_cleanup

This will find your installed prisma package and remove the auto-generated files.

If you're using a custom output location then all you need to do is pass the import path, the same way you do to use the client in your code, for example:

python -m prisma_cleanup app.prisma

Project name change

The name change that occurred in the last release has been reverted, see #300 for reasoning.

v0.6.0

2 years ago

Bug Fixes

  • Fix transformation of fields nested within a list (#264)

What's Changed

Client renamed to Prisma

In order to improve readability, the recommended method to import the client has changed from Client to Prisma. However, for backwards compatibility you can still import Client.

from prisma import Prisma

prisma = Prisma()

Removed redundant subclass warning when using FastAPI

By default a warning is raised when you attempt to subclass a model while using pseudo-recursive types, see the documentation for more information.

This warning was raised when using a Prisma model in a FastAPI response model as FastAPI implicitly subclasses the given model. This means that the warning was actually redundant and as such has been removed, the following code snippet will no longer raise a warning:

from fastapi import FastAPI
from prisma.models import User

app = FastAPI()

@app.get('/foo', response_model=User)
async def get_foo() -> User:
    ...

Prisma upgrade

The internal Prisma binaries that Prisma Python makes use of have been upgraded from v3.8.1 to v3.9.1. For a full changelog see the v3.9.0 release notes and v3.9.1 release notes.

Removing the HTTP timeout

You can now completely remove the internal HTTP timeout

from prisma import Prisma

prisma = Prisma(
    http={
        'timeout': None,
    },
)

Project Name Change

This project has been renamed from Prisma Client Python to Prisma Python

Attributions

Thanks to @ghandic for the bug report and thanks to @kivo360 for contributing!

v0.5.0

2 years ago

Bug Fixes

  • Removed relational fields from update_many mutation data, updating relational fields from update_many is not supported yet (https://github.com/prisma/prisma/issues/3143).
  • Fixed relational ordering typing, this was typed to order by the parent model, not the relational model (#234)
  • Fixed ordering typing to signify that only one field can be ordered by at once (pass a list if you need to order by multiple fields)

What's Changed

Dropped support for Python 3.6

Python 3.6 reached its end of life on the 23rd of December 2021. You now need Python 3.7 or higher to use Prisma Client Python.

Grouping records

You can now group records by one or more field values and perform aggregations on each group!

It should be noted that the structure of the returned data is different to most other action methods, returning a TypedDict instead of a BaseModel.

For example:

results = await Profile.prisma().group_by(
    by=['country'],
    sum={
        'views': True,
    },
)
# [
#   {"country": "Canada", "_sum": {"views": 23}},
#   {"country": "Scotland", "_sum": {"views": 143}},
# ]

For more examples see the documentation: https://prisma-client-py.readthedocs.io/en/stable/reference/operations/#grouping-records

While the syntax is slightly different the official Prisma documentation is also a good reference: https://www.prisma.io/docs/concepts/components/prisma-client/aggregation-grouping-summarizing#group-by

Improve support for custom generator options

You can now easily (and with full type-safety) define custom options for your own Prisma Generators!

from pydantic import BaseModel
from prisma.generator import GenericGenerator, GenericData, Manifest


# custom options must be defined using a pydantic BaseModel
class Config(BaseModel):
    my_option: int


# we don't technically need to define our own Data class
# but it makes typing easier
class Data(GenericData[Config]):
    pass


# the GenericGenerator[Data] part is what tells Prisma Client Python to use our
# custom Data class with our custom Config class
class MyGenerator(GenericGenerator[Data]):
    def get_manifest(self) -> Manifest:
        return Manifest(
            name='My Custom Generator Options',
            default_output='schema.md',
        )

    def generate(self, data: Data) -> None:
        # generate some assets here
        pass


if __name__ == '__main__':
    MyGenerator.invoke()

Removal of deprecated arguments

There are two arguments that were deprecated in previous releases that have now been removed:

  • The redundant encoding argument to Base64.decode()
  • The redundant order argument to actions.count()

Support for updating unique fields

You can now update fields that are marked as @unique or @id:

user = await User.prisma().update(
    where={
        'email': '[email protected]',
    },
    data={
        'email': '[email protected]',
    },
)

Custom CLI binary

You can now easily replace the Prisma CLI binary that Prisma Client Python makes use of by overriding the PRISMA_CLI_BINARY environment variable. This shouldn't be necessary for the vast majority of users however as some platforms are not officially supported yet, binaries must be built manually in these cases.

Prisma upgrade

The internal Prisma binaries that Prisma Client Python makes use of have been upgraded from v3.7.0 to v3.8.1. For a full changelog see the v3.8.0 release notes.

Miscellaneous changes

  • The Prisma Studio CLI entrypoint is not supported, the error message for this has been improved and points out the two solutions.