8 ms·
Show HN: Prisma Python – A fully typed ORM for Python
I created this ORM to fill a gap in the Python ecosystem. Due to the nature of typing in Python there are no other Python ORMs that can provide correct type hints. Prisma Python manages to work around this by auto-generating python types.
Aside from static type checking, providing type hints means that you will get autocomplete suggestions for you which for me is the killer feature for this ORM (see the GIF in the README for an example).
It's also built on top of Prisma, a next-generation ORM for TypeScript which means that the core query building and connection handling has been battle tested, getting around a potential concern with adopting a new ORM.
Prisma Python also supports PostgreSQL, SQLite, MongoDB, MariaDB and more!
- deleted 5y ago[deleted]
- melony 5y agoMight want to explain in the README that Prisma's core is written in Rust. You don't need to install an entire JS stack to use this.
- probablyrobert 5y agoGood point, I'll update it, thanks!
- BozeWolf 5y agoYes! I was looking for this as well.
- bckr 5y agoThis looks really cool. I might have to try it for my current project. Question: The Readme says there's room for massive improvement in performance. What's the performance like right now? Any benchmarks?
- probablyrobert 5y agoI haven't written benchmarks yet but it is something I am working on. The reason that performance is mentioned in the README is that I haven't spent time on improving it yet. The biggest blockers in terms of performance are: - Communication with the internal Rust engine is performed over HTTP instead of FFI. - You cannot select a subset of fields (every scalar field in a model is selected) - You cannot skip pydantic validation which while fast is unnecessary in some cases With that said Prisma Python should be reasonably fast but I would expect it to be on the lower end of the spectrum compared to other Python ORMs. I have ran some load tests locally and creating 500,000 records took about 90 seconds.
- anentropic 5y agoWhat is the Rust engine doing here? How come GitHub doesn't highlight any Rust code in the project repo?
- probablyrobert 5y agoBecause Prisma Python currently interfaces with the Rust engine over HTTP (I am looking into changing this) and the Rust engines can be found here: https://github.com/prisma/prisma-engines https://github.com/prisma/prisma-engines
- bb88 5y agoGiven the state of PyPi these days and third party packages, I would just prefer to have pure python, even if it is slower. It means I don't have to worry about things breaking on cross compilation between mac/windows/linux.
- probablyrobert 5y agoNo need to worry, the current behaviour will be preserved :) The method used to interface with the internal engine will be able to be configured in the schema: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#fields-1 https://www.prisma.io/docs/reference/api-reference/prisma-sc...
- WaitWaitWha 5y agoNowhere is the acronym ORM explained, let alone how it can benefit Python programmers.
- probablyrobert 5y agoORM stands for Object Relational Mapper and is essentially a wrapper over raw SQL queries to provide an easier to use interface.
- WaitWaitWha 5y agoThank you. I heard of ORM, My comment was mostly to enhance the readme.
- tomrod 5y agoTo add to this answer, an ORM is useful to deploy queries across multiple database vendors (e.g. Oracle, Postgres, SQLite) without re-writing queries. When used correctly it sanitizes SQL as well as supports with typing, as this library assist with. Though to add to another comment, this is pretty basic in the CRUD and front-end world, and learning how to learn when confronted with unfamiliar information is a very useful life skill.
- occz 5y agoPresumably a lot of Python-developers already know what an ORM is and how they can benefit from it, in particular given how long SQLAlchemy has been around. The rest can presumably hit up their favourite search engine and type in 'ORM', hit 'Search' and learn quite quickly what it is.
- deleted 5y ago[deleted]
- Havoc 5y ago> The rest can presumably hit up their favourite search engine and type in 'ORM' Thats missing the point quite badly. You don't want anything in the opening sentence of you site triggering users navigating away / switching to another browser tab
- lytefm 5y agoThis looks promising. Using prisma both in TypeScript app backends and in Python data pipelines would make switching between the two without much cognitive overhead much easier. I'll probably oppose introducing a different Python ORM at work until Prisma Python reaches 1.0
- probablyrobert 5y agoThanks :) Yeah that is understandable, it is being successfully used in production but it is safer to use a more stable ORM for mission critical products. If you don't want to have to duplicate your model definitions you could write a custom Prisma Generator to generate models for a different Python ORM. https://prisma-client-py.readthedocs.io/en/stable/reference/custom-generators/ https://prisma-client-py.readthedocs.io/en/stable/reference/...
- lytefm 5y agoNice, sharing the models across Codebases but only doing the migrations on one side is definitely what I'd be looking for.
- samwillis 5y ago> by auto-generating python types I'm assuming you are using a code generator? My understanding is that as MyPy is a static analyser there is no way to automatically create types at runtime (which is actually super annoying, particularly for a language as dynamic as Python).
- probablyrobert 5y agoYou are correct, we use code generation to define the query API types.
- dragonwriter 5y agoYou can create Python types at runtime, and Python’s runtime type checking features predate it's static analyzers. Unfortunately, the additional kinds of objects used for typechecking in the static analyzers (beyond those which are also runtime types) don’t work with runtime type checking, nor do static type declarations (even using types that are also runtime types.) (And, obviously, AOT static analyzers can’t make use of types that don’t exist when they run.)
- probablyrobert 5y agoYes it is rather unfortunate, Python's typing system doesn't support dynamically creating types like you can in TypeScript :/
- dllthomas 5y ago> dynamically creating types Could you explain what you mean by this? I'm not clear on what typescript behavior this describes.
- joshribakoff 5y agoMaybes mapped types are an example? https://www.typescriptlang.org/docs/handbook/2/mapped-types.html https://www.typescriptlang.org/docs/handbook/2/mapped-types....
- cabalamat 5y ago> Prisma, a next-generation ORM for TypeScript which means that the core query building and connection handling has been battle tested, getting around a potential concern with adopting a new ORM. Can I suggest you put this at the top of your README.md file, as I had never heard of Prisma before and it would have helped. > Prisma Python Is your program called Prisma Python or Prisma Client Python? You seem to be inconsistent with naming.
- probablyrobert 5y agoThanks for the feedback, I will add that. > Prisma Python I originally decided to go with Prisma Client Python however I found this to be too verbose and have recently used Prisma Python. I do need to decide on one and stick with that. Thanks for pointing that out
- mdellavo 5y agofully typed? it used dicts for queryinb - should maybe look at sqlalchemy for comparison
- probablyrobert 5y agoYes it is fully typed because of TypedDicts, https://docs.python.org/3/library/typing.html#typing.TypedDict https://docs.python.org/3/library/typing.html#typing.TypedDi... SQLAlchemy on the other hand provides very little (if any) type hints for their query API.
- klft 5y agoSeems to solve the same problem as SQLModel. From [1]: "SQLModel is a library for interacting with SQL databases from Python code, with Python objects. It is designed to be intuitive, easy to use, highly compatible, and robust. SQLModel is based on Python type annotations, and powered by Pydantic and SQLAlchemy." [1] https://sqlmodel.tiangolo.com/ https://sqlmodel.tiangolo.com/
- probablyrobert 5y agoYes it is similar to SQLModel however as SQLModel is based off of SQLAlchemy, the query API is not typed. That is the difference.
- O5vYtytb 5y agoAFAIK SQLAlchemy 2.0 (coming soon?) will use a new system for full typing.
- probablyrobert 5y agoYes I had heard about that but due to the nature of Python typing, they can't actually type the query API properly without falling back to Any, negating the benefits of type checking.
- klft 5y agoMy understanding is that this is exactly what SQLModel adds on top of SQLAlchemy. statement = select(Hero).where(Hero.age > 32).limit(3) But I am only halfway through the tutorial so I might be wrong. HN discussion of SQLModel here [1] [1] https://news.ycombinator.com/item?id=28294534 https://news.ycombinator.com/item?id=28294534
- probablyrobert 5y agoMy understanding of SQLModel is that it brings the benefits of both Pydantic and SQLAlchemy. The benefit of merging Pydantic with SQLAlchemy is that you can then use the database models directly in FastAPI route definitions.
- djstein 5y ago@propbablyrobert great job on this! I hope you can get buy-in from the Prisma team for support. This would be great for their moat.
- probablyrobert 5y agoThank you! I hope so too, it would be incredibly helpful.
- sorenbs 5y agoThis is really cool! We (Prisma) would love to support this project in any way we can. You can find my email in bio if you are interested in a call :-)
- MaxMoney 5y ago
- leetrout 5y agoA comment from a previous Prisma post > under the hood @prisma/client was spinning up it's own GraphQL server that it would send requests to in order to generate SQL to send to postgres[1] So is this the same approach you are taking with the HTTP API? [1] https://news.ycombinator.com/item?id=26889543 https://news.ycombinator.com/item?id=26889543
- probablyrobert 5y agoYes I am using the same approach however I am working on using native FFI bindings which is what the TypeScript client is using now. https://github.com/RobertCraigie/prisma-client-py/pull/165 https://github.com/RobertCraigie/prisma-client-py/pull/165
- leetrout 5y agoThat's great. I think it makes it such an easy onramp to integrate with something by having HTTP based APIs (or really, gRPC, even) even if it is lower performance compared to native libraries. Looking forward to trying this.
- crucialfelix 5y agoI use Prisma typescript daily and love it. It's fast to write complex queries and readable joins. The type hints are well documented and custom generated for your models and relationships. It would be great if Prisma could support yet more languages! It's a great product. That said, I would not have two backends sharing the same database, even if one is the master that runs migrations. A component should only have one reason to change.
- probablyrobert 5y agoYeah, sharing the same database between two backends would not be a good idea. That said you do not have to use the TypeScript client at the same time as the Python client, they are independent of each other.
- joshribakoff 5y agoI use Prisma and it’s far from perfect but what I love about it is you can introspect a legacy database and generate a Prisma schema, and use the database as the source of truth. You’re not tied to a 1:1 relationship between classes and tables, and the correctness of the types do not depend on tediously annotating code correctly. Excited to see more languages supported!
- post-it 5y agoAre there any ORMs that do that currently? That sounds awesome
- ParetoOptimal 5y agoSee F# and it's type providers.
- probablyrobert 5y agoIf you're wanting to automatically generate the Prisma Schema then all you have to do is create the schema file, define the datasource connection and then run `prisma db pull`
- ChibiJoel 5y agoIndeed! https://www.prisma.io/docs/concepts/components/introspection https://www.prisma.io/docs/concepts/components/introspection
- camdenreslink 5y agoEntity Framework allows you to do that (if you are coding for .NET). It is the best ORM I've encountered. The option to do it is called "Code First from Database".
- dpacmittal 5y agoMikroORM can also auto generate schema from an existing database
- PeterCorless 5y agoNice! I opened a feature request for it already and shared with our Python community.
- probablyrobert 5y agoThank you for sharing! It is much appreciated!
- PeterCorless 5y agoAlso, the ticket I opened was promptly replied to and politely closed. This is actually an issue already open under this ticket: https://github.com/prisma/prisma/issues/2879 https://github.com/prisma/prisma/issues/2879
- hutrdvnj 5y agoIs it just me who thinks that plain SQL has won the SQL vs ORM battle? I mean why should I learn how to use X different ORM syntaxes in Y different languages and in addition to that lose full control over the actual query.
- probablyrobert 5y agoUse whatever works for you! I personally felt the same until I learned of Prisma. The main benefits for me are type checking and autocomplete. Autocomplete is the big one as it lessens the learning curve immensely. You no longer have to search through documentation to find a relevant method, you simply have to trigger autocomplete and it'll show you what you can do!
- NAHWheatCracker 5y agoThat's how I've personally felt since I first encountered ORMs a decade ago at a data intensive startup where ORMs were a burden. Yet I keep running into ORMs. Luckily, they are better implemented at my current job. I still think it gets in the way quite often, but I recognize that it enables some outsized returns on effort. Entire REST APIs can be generated with things like Spring Data. SqlAlchemy can be pretty slick in Python. I still write raw SQL on my personal projects, but I recognize that I have to spend a lot of time doing that.
- ckmar 5y agoBig fan of queries being written in SQL and yielding pure, properly structured business objects. An example of this approach is PureORM[0] [0]https://github.com/craigmichaelmartin/pure-orm https://github.com/craigmichaelmartin/pure-orm
- inshadows 5y agoHow is this DSL acceptable? posts = await client.post.find_many( where={ 'OR': [ {'title': {'contains': 'prisma'}}, {'content': {'contains': 'prisma'}}, ] } ) SQL for comparison: ... where title like '%prisma%' or content like '%prisma%'
- lucas_codes 5y agoNow try filtering on a relation!
- probablyrobert 5y agoI find the relational API very easy and intuitive to work with. What do you not like about it?
- lucas_codes 5y agoSo do I - the parent is choosing to compare the most basic example which didn't show the benefits of using an orm over raw sql
- probablyrobert 5y agoAh sorry I misread your comment, I thought you were agreeing and saying that filtering by a relational field is also unacceptable DSL. Thank you :)
- subsection1h 5y agoThis is one of the things I've never understood about ORMs. They're not helpful for simple queries, but they're also not helpful for the most complex queries. When I've used ORMs in past (e.g., Active Record), we regularly needed to bypass the ORM to write raw SQL for complex queries in order to get the best performance.
- mypalmike 5y ago
- messo 5y agoHow does Prisma compare to EdgeDB? Pros and cons? I have limited experiences with DBs and ORMs, but EdgeDB looks very interesting.
- probablyrobert 5y agoI am not very familiar with EdgeDB but it is quite different to Prisma. EdgeDB is a database while Prisma is a database client. EdgeDB do provide their own clients to interface with the EdgeDB database but with Prisma you can connect to many different databases, e.g. PostgreSQL, SQLite, MongoDB etc
- RedCrowbar 5y agoThat's correct. Prisma is an ORM with all the pros and cons of being one. EdgeDB, on the other hand, is a brand new graph-relational database server, built on PostgreSQL. ORMs have the ability to work with multiple RDBMS implementations, but for that they trade away expressive power and efficiency. Prisma is fairly slow, especially when your query is fetching multiple relationships, because it does multiple DB roundtrips to fetch parts of the result and reconstitutes it on the client. ORM APIs are generally very limiting, as there is no general way of doing server-side computation (e.g. do a comparison on a substring of a string property or simply do arithmetic). EdgeDB does not have these problems, because its query language, EdgeQL, is designed to be efficiently embeddable into a programming language without any loss of expressive power or performance. At this moment we have a fully-featured TypeScript/JavaScript builder [1], with Python and Go coming soon. [1] https://www.edgedb.com/docs/clients/01_js/index#the-query-builder https://www.edgedb.com/docs/clients/01_js/index#the-query-bu... (Full disclosure: I work on EdgeDB)