WEBVTT

00:00:00.001 --> 00:00:04.740
If you could have any API you wanted to access data from Python, what would it look like?

00:00:04.740 --> 00:00:11.540
What would make it Pythonic? This week, you'll hear about Pony ORM. Pony is a Python ORM with

00:00:11.540 --> 00:00:16.260
beautiful query syntax that lets you write your database queries using Python generators and

00:00:16.260 --> 00:00:21.280
Lambdas. Join me in a conversation with one of Pony ORM's founders, Alexei Milošković.

00:00:21.280 --> 00:00:26.660
This is Talk Python To Me, episode 87, recorded November 3rd, 2016.

00:00:26.660 --> 00:00:56.220
Welcome to Talk Python To Me, a weekly podcast on Python, the language, the libraries, the

00:00:56.220 --> 00:01:00.840
ecosystem, and the personalities. This is your host, Michael Kennedy. Follow me on Twitter

00:01:00.840 --> 00:01:05.760
where I'm @mkennedy. Keep up with the show and listen to past episodes at talkpython.fm

00:01:05.760 --> 00:01:08.280
and follow the show on Twitter via at Talk Python.

00:01:08.280 --> 00:01:15.460
This episode has been sponsored by Rollbar and GoCD. Thank them both for supporting the podcast

00:01:15.460 --> 00:01:18.100
by checking out what they're offering during their segments.

00:01:18.100 --> 00:01:20.260
Alexei, welcome to Talk Python.

00:01:20.260 --> 00:01:21.600
Hi, Michael. Thank you.

00:01:21.780 --> 00:01:26.240
Yeah, it's great to have you here. Thanks for coming. I'm super excited to talk about your

00:01:26.240 --> 00:01:33.880
ORM and that you built this, what I'm saying might be the most Pythonic ORM yet, which because

00:01:33.880 --> 00:01:39.120
of the really cool query syntax that you use and a couple of other highly Pythonic techniques

00:01:39.120 --> 00:01:44.380
and I'm very impressed with it. But before we get into the details of Pony ORM, let's talk

00:01:44.380 --> 00:01:46.360
about your story. How'd you get into programming in Python?

00:01:46.660 --> 00:01:51.980
Well, I was always interested in programming, actually. When I was a teenager, I had a Sinclair

00:01:51.980 --> 00:01:58.520
ZX Spectrum computer, played computer games and started to program BASIC. And actually,

00:01:58.520 --> 00:02:04.200
it was the reason for me to get a master's degree in computer science later. I was programming

00:02:04.200 --> 00:02:09.900
while studying in the university, but what I really liked was computer networks. So after

00:02:09.900 --> 00:02:17.420
graduating, I started to work as a network engineer in an IT department of an airline company. And at

00:02:17.420 --> 00:02:26.340
that time, it was 2001 and 2002, airline agencies had to use dedicated list lines for connecting

00:02:26.340 --> 00:02:34.820
to airline database system. And I figured that using internet for that would be like 100% cheaper.

00:02:35.020 --> 00:02:42.140
And then I got that crazy idea of developing a client server solution, which works over internet.

00:02:42.140 --> 00:02:50.020
So I developed a prototype and it consisted of an app written in Delphi and a Linux server. And

00:02:50.020 --> 00:02:55.820
then I presented it to the airline management team. And they were impressed and offered me

00:02:55.820 --> 00:03:02.560
to form a development team. So from that point in time, I continued as a developer.

00:03:02.560 --> 00:03:08.320
Yeah, that's think of the times back when you had to have a leased line or back when you had

00:03:08.320 --> 00:03:13.840
BBSs, you had to dial up to get online. Like it's just such a different world, right? But

00:03:13.840 --> 00:03:17.400
that's really cool to help that company like emerge out of that world.

00:03:17.400 --> 00:03:21.500
Right. So now you cannot imagine that not using internet, right?

00:03:21.500 --> 00:03:22.320
Exactly.

00:03:22.320 --> 00:03:32.040
Yeah. So and then several years later, I started to work for another company. It was a fintech startup.

00:03:32.200 --> 00:03:38.600
It was a New York based company and they outsourced the development to St. Petersburg, Russia,

00:03:38.600 --> 00:03:47.600
this city where I'm originally from. And I was developing the backend in C++ and Java. And when

00:03:47.600 --> 00:03:53.620
the business took off, they decided to form a team, a development team in New York. And they

00:03:53.620 --> 00:04:01.320
invited me for this role. So I moved to New York and formed a development team there. And it was

00:04:01.840 --> 00:04:10.040
building software for seven years there. And during that time, actually, my friend, Alexander

00:04:10.040 --> 00:04:17.040
Kozlovsky, we studied together in the university. And he was really, really interested in databases.

00:04:17.240 --> 00:04:25.440
And he was actually a senior lecturer. So he taught people databases. And he feared that most

00:04:25.440 --> 00:04:32.640
people actually don't get relational algebra, you know, and there should be a better way to

00:04:32.640 --> 00:04:43.440
build software. He suggested an idea to build a web framework. And I love the idea because working

00:04:43.440 --> 00:04:53.640
for a financial company, I saw that it is a very fast environment. And I actually missed a tool like Delphia,

00:04:53.640 --> 00:05:05.640
rapid application development tool. And I thought that if I would have one, I would use one. And this is how we started to work on Pony. And it was a weekend project, actually, initially.

00:05:09.640 --> 00:05:21.840
And it was a template engine. It was routing. It was ORM. And then we found that probably we shouldn't do all those things because it's too much.

00:05:21.840 --> 00:05:22.840
Yeah.

00:05:22.840 --> 00:05:50.240
And by that time, by that time, Circle Alchemy appeared. Actually, we started the same year, 2006. It was the first year when we started to work together. And actually, by that time, Alexander already tried to build a mapper. He tried in C++ in Delphi. And Python was a choice which he came to understanding that it should be a dynamic language.

00:05:50.240 --> 00:06:01.440
Yeah, I'm sure it was much harder in C++ to pull something like this off, especially with the really rich language level query syntax. Like, I'm not really sure how that works in C++.

00:06:01.440 --> 00:06:24.440
Right. And then we started to work together on this. And he told that it was a SQL object, such a mapper. And in one of email lists, he suggested that why not to use generator syntax for writing queries. And I love the idea, too, because it was natural syntax for queries.

00:06:24.440 --> 00:06:44.380
It's a completely natural syntax. Like, I think of generator expressions and list comprehensions as kind of like in-memory database operations, just working on your objects, obviously not indexed or anything like that. So if you're going to do that in your Python code, but somehow project that down into the database, that's perfect, I think.

00:06:44.380 --> 00:06:58.820
Yeah, exactly. And what we liked as well, that it is so natural for someone who just starts working with Python, that you don't need to actually learn another language such as SQL.

00:06:59.160 --> 00:07:04.660
Yeah, I think you probably could get away with just being able to read but not write SQL with Pony.

00:07:04.660 --> 00:07:04.880
Yeah.

00:07:04.880 --> 00:07:18.000
Yeah. Or SQLAlchemy or some of the other ORMs, right? Like, if you can understand the debug output, you may be okay. Who knows? It depends on how complex I suppose it gets. But that's a cool goal anyway.

00:07:18.000 --> 00:07:29.460
Exactly. And I worked with people who actually can program different languages, but it's hard for them to understand SQL pretty well.

00:07:29.460 --> 00:07:35.480
And that's why we decided that if we could provide such a tool, it will be very helpful.

00:07:35.480 --> 00:07:40.000
And I could see how it can speed up making prototypes.

00:07:40.000 --> 00:07:48.840
And, you know, when you build a prototype, you never know if it will be an application later and how it will evolve.

00:07:48.840 --> 00:07:56.140
Yeah, absolutely. That means... I wonder how many applications there are in production in the world that were just supposed to be prototypes.

00:07:56.140 --> 00:07:58.060
I bet it's a really high percentage.

00:07:58.060 --> 00:08:02.980
Yeah, I agree. You need to have a tool which allows you to start quickly.

00:08:03.200 --> 00:08:13.760
And then when you actually evolve with this application evolves, you want it to allow you to build this as complex as you want.

00:08:13.760 --> 00:08:24.940
Well, yeah. And also the ability to recreate the project quickly rather than manage some huge data access layer with some kind of ORM that's really nice and clean.

00:08:24.940 --> 00:08:30.260
Like Pony ORM is a really good thing to have so you can say, no, no, this is a prototype.

00:08:30.380 --> 00:08:34.100
We're going to start again. But it only takes like this morning and then we'll have it back to where it is.

00:08:34.100 --> 00:08:36.280
But proper. Something like that, right?

00:08:36.280 --> 00:08:37.920
That's cool.

00:08:37.920 --> 00:08:45.200
An app that created using a simple tool can reach a point where the further development is too difficult or even impossible.

00:08:45.200 --> 00:08:54.000
And having reached this borderline of complexity, it's often no time actually to start from scratch.

00:08:54.300 --> 00:08:57.100
Yeah, it's usually you're already down that path and it's too late.

00:08:57.100 --> 00:08:58.440
How interesting.

00:08:58.440 --> 00:09:01.480
Okay, so let's talk about Pony ORM a bit.

00:09:01.480 --> 00:09:05.180
So Pony ORM is a data access layer.

00:09:05.180 --> 00:09:08.200
It's an ORM, object relational mapper.

00:09:08.200 --> 00:09:11.480
How would you describe it if somebody asked you what is Pony ORM?

00:09:11.620 --> 00:09:20.200
Well, it is an advanced object relational mapper and it provides a very easy interface.

00:09:20.200 --> 00:09:23.680
And even a newbie can start working with this.

00:09:23.820 --> 00:09:34.700
That is one thing I was struck with when I was working with it is I was almost thinking like, well, how do I connect back this object to the entities?

00:09:34.700 --> 00:09:37.420
Like, where do I create the entity base class from?

00:09:37.420 --> 00:09:42.600
And how do I, you know, why don't I have to call add to insert objects?

00:09:42.600 --> 00:09:44.680
And why don't I have to call commit to commit them?

00:09:44.900 --> 00:09:56.060
And all of those answers are because you're using some really interesting Pythonic concepts that sort of simplify a couple of the steps that you might have found in other ORMs.

00:09:56.060 --> 00:09:56.720
Right.

00:09:56.720 --> 00:09:59.940
And Pony, it's a small horse, right?

00:09:59.940 --> 00:10:02.740
It's small, smart, and powerful.

00:10:02.740 --> 00:10:08.460
So we believe that these features we put into our mapper.

00:10:08.660 --> 00:10:09.440
I think so, too.

00:10:09.440 --> 00:10:12.100
I think it's really, it is really nice.

00:10:12.100 --> 00:10:16.880
And I'm looking forward to using it properly on some projects now that I know a little bit more about it.

00:10:16.880 --> 00:10:20.560
So I want to ask you what's Pythonic about it.

00:10:20.560 --> 00:10:27.000
But I think maybe the way to uncover the various Pythonic elements is to actually work through an example.

00:10:27.000 --> 00:10:30.940
But before we get to that, let me ask you this other question.

00:10:30.940 --> 00:10:37.040
So there's these two styles or two design patterns that typically are in play at ORMs.

00:10:37.880 --> 00:10:46.340
And that's whether or not the ORM acts as an active record where you sort of work with individual elements.

00:10:46.340 --> 00:10:51.440
So like Ruby on Rails or I think the Django ORM is like this.

00:10:51.440 --> 00:11:00.560
Or it's a unit of work, which is like SQLAlchemy, where you create a bunch of objects and make some changes, inserts, updates, deletes, and so on.

00:11:00.560 --> 00:11:04.260
And when you're finally ready, you commit that unit of work and it applies all of those.

00:11:04.260 --> 00:11:05.720
Which style is Pony?

00:11:05.720 --> 00:11:07.100
Yeah, absolutely.

00:11:07.100 --> 00:11:09.440
There are two basic patterns.

00:11:09.440 --> 00:11:16.260
And with active record, you have an object which represents a line in the database.

00:11:16.900 --> 00:11:27.400
And the thing is that if you select the same object twice using active record, you will have two instances of the same object in the memory.

00:11:27.400 --> 00:11:35.240
And it is a huge problem because now you have two objects which are actually the same.

00:11:35.240 --> 00:11:37.580
And when you start to change one object.

00:11:37.580 --> 00:11:40.740
And then change another one, you can have lost updates.

00:11:40.740 --> 00:11:47.080
And another thing that you need to always remember to call safe on each object.

00:11:47.080 --> 00:11:47.700
Yeah, exactly.

00:11:47.700 --> 00:11:50.140
And you don't really do that with unit of work.

00:11:50.140 --> 00:11:51.940
You just kind of work with your data.

00:11:51.940 --> 00:11:54.280
And when you're ready, you commit it, right?

00:11:54.280 --> 00:12:04.320
Every time you read a record from the database, we first check in the identity map if there is such a record already loaded into the memory.

00:12:04.440 --> 00:12:15.060
And this allows us to return an object from the cache from the memory instead of querying the database.

00:12:15.060 --> 00:12:20.880
Yeah, so that's cool in that it gives you better performance because you're not round-tripping to the database as often.

00:12:20.880 --> 00:12:29.060
But it's also maybe even more important that it means if you somehow get the same object twice, it's still the same object in memory, right?

00:12:29.060 --> 00:12:29.780
Exactly.

00:12:29.780 --> 00:12:34.760
So it allows us to avoid excessive database calls.

00:12:34.760 --> 00:12:39.700
And at the same time, we always work with the same copy of the object.

00:12:40.180 --> 00:12:46.860
And another option that it provides us with is to manage transactions.

00:12:46.860 --> 00:12:52.620
So we can see when the scope of a function or a context manager was left.

00:12:52.620 --> 00:12:57.380
And at this point, we can commit all the changes to the database.

00:12:57.380 --> 00:12:58.400
It is very convenient.

00:12:58.400 --> 00:12:59.580
Yeah, that's very convenient.

00:12:59.580 --> 00:13:02.600
I love your use of context managers in this project.

00:13:02.600 --> 00:13:06.260
So maybe that's a good place to jump into talking about the code.

00:13:06.260 --> 00:13:10.040
And we have to be a little careful on audio format talking about code.

00:13:10.040 --> 00:13:15.880
But maybe we could just kind of roughly walk through some of the steps involved.

00:13:15.880 --> 00:13:19.640
And we could talk about the Pythonic concepts as we get to them.

00:13:19.640 --> 00:13:20.120
Okay.

00:13:20.120 --> 00:13:21.760
So obviously, yeah.

00:13:21.760 --> 00:13:25.280
So obviously, to get started, you have to import Pony, right?

00:13:25.280 --> 00:13:29.040
So there's a number of things in there that you got to work with.

00:13:29.040 --> 00:13:32.040
So pip install Pony, import Pony, and so on.

00:13:32.040 --> 00:13:34.540
And then you create a database.

00:13:35.140 --> 00:13:38.120
So a database is just an object, right?

00:13:38.120 --> 00:13:43.720
But this database has a couple of features that go on to be super important.

00:13:43.720 --> 00:13:48.320
Like on that object, you have a base class.

00:13:48.320 --> 00:13:50.900
And all of your entities have to derive from it, right?

00:13:50.900 --> 00:13:51.580
Exactly.

00:13:52.060 --> 00:13:55.680
So when you create a database, at this point, it is just an object.

00:13:55.680 --> 00:14:03.680
And later, when you create entities, you inherit it from db.entity, which is an attribute.

00:14:03.680 --> 00:14:12.140
And it is abstract class, which tells that it is an entity which is connected to this database.

00:14:12.140 --> 00:14:17.040
And having such pattern, actually, you can create several databases.

00:14:17.480 --> 00:14:20.500
You can simultaneously work with more than one database.

00:14:20.500 --> 00:14:21.220
Right.

00:14:21.220 --> 00:14:28.360
Maybe you have like a core database that has your important stuff and then an analytics database for tracking how people are using your app.

00:14:28.360 --> 00:14:29.100
Something like that, right?

00:14:29.100 --> 00:14:29.480
Yeah.

00:14:29.480 --> 00:14:31.300
It's very often used this way.

00:14:31.300 --> 00:14:31.580
Yeah.

00:14:31.580 --> 00:14:36.100
And then you create, like you said, you create this class that derives from db.entity.

00:14:36.100 --> 00:14:38.860
What does it look like to define the columns?

00:14:38.860 --> 00:14:45.800
The main difference of Pony from other mappers is that we work in terms of entities.

00:14:45.800 --> 00:14:51.180
So in SQLAlchemy, you work with relations.

00:14:51.180 --> 00:15:01.040
And here with Pony, we hire the level of abstraction and work in terms of entities, in terms of objects.

00:15:01.980 --> 00:15:04.080
And we don't create columns.

00:15:04.080 --> 00:15:06.380
We create attributes of the object.

00:15:06.380 --> 00:15:13.340
Because this way, we figure that it is easier for a human being to think in terms of objects, not relations.

00:15:13.340 --> 00:15:13.700
Yeah.

00:15:13.700 --> 00:15:15.400
And probably Python as well, right?

00:15:15.400 --> 00:15:18.660
We're used to working with hierarchical collections of objects anyway.

00:15:18.660 --> 00:15:19.760
Yeah.

00:15:19.760 --> 00:15:20.220
Yeah.

00:15:20.220 --> 00:15:21.680
And then you create attributes.

00:15:21.680 --> 00:15:27.200
And we provide a very concise way of declaring such entities.

00:15:27.200 --> 00:15:32.460
Because from the first day of developing Pony, we actually had three goals.

00:15:32.460 --> 00:15:36.340
We wanted this mapper would be easy to use.

00:15:36.340 --> 00:15:38.700
It means having PyTonic API.

00:15:38.700 --> 00:15:40.780
It should be very performant.

00:15:40.780 --> 00:15:42.460
So high performance is the goal.

00:15:42.460 --> 00:15:46.560
And the third is safety and reliability.

00:15:47.180 --> 00:15:52.940
So we would like to avoid SQL injections and make it reliable.

00:15:52.940 --> 00:15:53.360
Yeah.

00:15:53.360 --> 00:15:56.040
You do some really nice stuff to avoid SQL injection attacks.

00:15:56.040 --> 00:15:57.940
And I'll talk about those later as well.

00:15:57.940 --> 00:15:58.440
Yeah.

00:15:58.440 --> 00:16:02.640
So when you declare entities, it is as short as possible.

00:16:02.640 --> 00:16:07.080
You just write the attribute name and then the type of the attribute.

00:16:07.080 --> 00:16:11.060
So it could be a required attribute or optional.

00:16:11.060 --> 00:16:18.020
Another two options is you can have a primary key or a relationship to another entity.

00:16:18.880 --> 00:16:31.760
And then in creating the attribute, you specify the type of the attribute and some additional options like unique or auto generator.

00:16:31.760 --> 00:16:41.340
When you want to have a sequence creating a new object, sometimes you want ID to be automatically generated.

00:16:41.440 --> 00:16:41.620
Right.

00:16:41.620 --> 00:16:45.820
And of course, you have default values as well for like created dates and things like that, right?

00:16:45.820 --> 00:16:46.400
Right.

00:16:46.400 --> 00:16:48.580
So we have API reference.

00:16:48.580 --> 00:16:55.240
And there are about like probably 15 options that you can specify for attribute.

00:16:55.240 --> 00:16:57.480
And you asked about columns.

00:16:57.480 --> 00:16:59.980
You can also specify the name of the column.

00:17:00.340 --> 00:17:13.560
If you would like to give a specific name to the database column or if you have a database already created and you would like to map these entities to the existing tables.

00:17:13.560 --> 00:17:19.220
So you can specify the table name and the column name declaring the entity.

00:17:19.220 --> 00:17:20.380
Yeah, that's excellent.

00:17:20.380 --> 00:17:22.780
So let me try to give people a really quick example here.

00:17:22.920 --> 00:17:28.000
So you've on your GitHub, you've got a nice example called eStore.

00:17:28.000 --> 00:17:35.240
And you have relationships between like customers and products and stuff in a shopping cart and so on.

00:17:35.240 --> 00:17:40.940
So you obviously have a customer class and a product class and so on.

00:17:40.940 --> 00:17:42.640
But just to like talk about the simplicity.

00:17:42.640 --> 00:17:48.040
So for a cart item, the whole thing is you have a cart item class that drives from db.entity.

00:17:48.300 --> 00:17:52.440
It has a quantity, which is a required column, which is an integer.

00:17:52.440 --> 00:17:56.240
And then you have a customer, which is a required customer object.

00:17:56.240 --> 00:18:01.780
Just literally parentheses the class name, not even in quotes, just actually the Python class object.

00:18:01.780 --> 00:18:06.040
And product required of product.

00:18:06.040 --> 00:18:12.000
So here's an object that has two relationships back to customer and product.

00:18:12.000 --> 00:18:15.680
And it's like the simplest thing you can imagine, right?

00:18:15.680 --> 00:18:16.020
Right.

00:18:16.320 --> 00:18:28.240
In order to make it even simpler, you can take a look at the diagram at our entity relationship diagram editor, which represents this database schema.

00:18:28.240 --> 00:18:30.520
So you can visually see this.

00:18:30.520 --> 00:18:30.940
Right.

00:18:30.940 --> 00:18:41.060
So for people who are listening, if they want to find it and they don't want to go in the show notes, it's editor.ponyorm.com slash user slash pony slash E capital S store.

00:18:41.060 --> 00:18:42.880
Of course, I'll link to that.

00:18:42.880 --> 00:18:45.000
Yeah, that's really cool.

00:18:45.000 --> 00:18:51.020
And you guys have this wonderful online designer that shows you the relationships that lets you model and rearrange them.

00:18:51.020 --> 00:18:56.800
Even get the what would be the generated SQL, the generated Python classes, and so on.

00:18:56.920 --> 00:19:01.020
Definitely, I want to come back and talk about this online editor because it looks really special.

00:19:01.020 --> 00:19:02.320
So, yeah.

00:19:02.320 --> 00:19:02.880
So very cool.

00:19:02.880 --> 00:19:07.620
We create these entities and the relationships are really super simple to set up.

00:19:07.620 --> 00:19:08.700
So that's wonderful.

00:19:08.700 --> 00:19:16.100
And then another thing that you chose to do in your API is make the ID something that is optional.

00:19:16.100 --> 00:19:16.780
Right.

00:19:17.140 --> 00:19:20.320
Oftentimes, you don't have a natural primary key.

00:19:20.320 --> 00:19:20.520
Yeah.

00:19:20.520 --> 00:19:28.580
And in this case, you just create attributes that you want to have in the entity.

00:19:29.160 --> 00:19:33.120
And if you don't declare primary key, pony will add it automatically.

00:19:33.120 --> 00:19:37.920
And it will be integer type with sequence.

00:19:37.920 --> 00:19:40.540
Yeah, the auto-incrementing primary key.

00:19:40.540 --> 00:19:40.900
Exactly.

00:19:41.080 --> 00:19:41.240
Yeah.

00:19:41.240 --> 00:19:41.900
Yeah.

00:19:41.900 --> 00:19:43.060
Yeah, that's perfect.

00:19:43.060 --> 00:19:44.960
So then you go through the standard stuff.

00:19:44.960 --> 00:19:47.440
You bind to a database connection and a database type.

00:19:47.720 --> 00:19:50.720
What types of databases are supported?

00:19:50.720 --> 00:19:59.100
So currently, we support four major databases, which are SQLite, Postgres, MySQL, and Oracle.

00:19:59.100 --> 00:20:05.180
And currently, we are working on adding Microsoft SQL Server.

00:20:05.180 --> 00:20:12.400
So we had users who asked us about it, and we actually added this type of database.

00:20:12.720 --> 00:20:18.540
But the thing is that recently, we added a JSON type support.

00:20:18.540 --> 00:20:26.620
So you can work with the database JSON type and make queries to those JSON types.

00:20:26.620 --> 00:20:30.960
And this part, we didn't add to Microsoft Server yet.

00:20:30.960 --> 00:20:38.700
But after we will add the JSON support, I think we will include it into the release, and we'll support five databases.

00:20:38.700 --> 00:20:39.720
Oh, that sounds great.

00:20:39.720 --> 00:20:42.280
I mean, those are basically the major ones.

00:20:42.280 --> 00:20:48.200
Are there any that people are asking for that are asking for commonly that are missing?

00:20:48.200 --> 00:20:52.200
Only a Microsoft SQL Server was something we were asking about.

00:20:52.200 --> 00:20:54.400
Yeah, it seems to me like those five rounded out.

00:20:54.400 --> 00:20:56.500
Tell me more about this JSON thing.

00:20:56.500 --> 00:21:04.200
Is this something that is JSON stored in like Postgres or SQLite, or is it something else?

00:21:04.200 --> 00:21:04.920
Right.

00:21:05.040 --> 00:21:07.960
So we used the native database JSON type.

00:21:07.960 --> 00:21:14.140
So it is JSON B, binary JSON for progress and for MySQL.

00:21:14.140 --> 00:21:17.500
For Oracle, it is, I believe it is Club.

00:21:17.500 --> 00:21:23.380
And for SQLite, normally it is stored as text by default.

00:21:23.540 --> 00:21:28.620
But you always can install a module, which is called JSON 1.

00:21:29.660 --> 00:21:33.700
And this way, your queries to SQLite will be faster.

00:21:33.700 --> 00:21:36.420
Okay, so there's a module that I can extend.

00:21:36.420 --> 00:21:37.480
I see.

00:21:37.480 --> 00:21:46.260
That I can extend SQLite so that it can understand the internals of that JSON document so I could possibly query by some attribute deep down inside it.

00:21:46.260 --> 00:21:50.320
Recently, we have added native JSON data type support.

00:21:50.320 --> 00:21:56.860
And this way, we can actually combine NoSQL database with a relational database.

00:21:56.860 --> 00:21:59.780
So it's like having best of two worlds.

00:21:59.780 --> 00:22:05.820
In a relational database, you can declare an attribute of JSON type.

00:22:05.820 --> 00:22:12.160
And in this attribute, you can keep the data structure, which can vary.

00:22:12.160 --> 00:22:13.800
Yeah, this is really cool.

00:22:13.800 --> 00:22:21.580
So basically, you have regular columns, but you can also have hierarchical columns that are stored as JSON, more or less.

00:22:21.580 --> 00:22:22.300
That's right.

00:22:22.300 --> 00:22:30.140
Yeah, it does very much seem like here's a MongoDB type thing going on as part of that table.

00:22:30.140 --> 00:22:30.660
Exactly.

00:22:30.660 --> 00:22:40.880
And you can actually do queries to the internals of this JSON structure, which is described in our documentation.

00:22:40.880 --> 00:22:41.920
Yeah, yeah, that's cool.

00:22:41.920 --> 00:22:45.960
Can you add indexes to the internals of that data structure?

00:22:45.960 --> 00:22:47.520
I think not yet.

00:22:47.520 --> 00:22:50.640
It's down to whether the database is supported, I'm sure.

00:22:50.640 --> 00:22:54.840
Probably if the database supports that, you can...

00:22:54.840 --> 00:22:59.180
Actually, it is just a native JSON type for the database.

00:22:59.180 --> 00:23:02.840
If a database supports index, you can add an index.

00:23:02.840 --> 00:23:03.220
Right.

00:23:03.220 --> 00:23:04.080
Okay, that makes sense.

00:23:04.160 --> 00:23:10.760
So it's really a question of, does MySQL support indexes on embedded JSON types, which I actually don't know the answer to.

00:23:10.760 --> 00:23:12.660
So that's cool, though.

00:23:12.660 --> 00:23:16.080
We have users who use this feature in production already.

00:23:16.080 --> 00:23:16.520
Nice.

00:23:16.520 --> 00:23:21.920
So yeah, speaking of production, can you speak of some of the notable deployments of PonyRM?

00:23:22.380 --> 00:23:25.940
I mean, I know the vast majority of no visibility into, but...

00:23:25.940 --> 00:23:35.340
Yeah, some of them asked us not share their details because they have PR departments that they need to approve it with.

00:23:35.340 --> 00:23:41.200
And for those who we can share, I put testimonials to our site.

00:23:41.540 --> 00:23:42.100
Oh, yeah, excellent.

00:23:42.100 --> 00:23:45.980
I see at the bottom, there's a whole bunch of testimonials and people can come check them out.

00:23:45.980 --> 00:23:53.280
I'm sure not everybody has permission to divulge whether they're, you know, speak on behalf of their company, but that's very cool.

00:23:53.280 --> 00:24:01.780
So when I was working on the new version of the site, I sent this request to all our users.

00:24:01.780 --> 00:24:10.240
And actually, those people paid for the license because initially we had Pony released under dual license.

00:24:10.440 --> 00:24:14.060
So it was AGPL and it was commercial license.

00:24:14.060 --> 00:24:19.420
And then we figured that AGPL actually doesn't really work with the community.

00:24:19.420 --> 00:24:21.660
People don't like AGPL at all.

00:24:21.660 --> 00:24:34.100
And although we were selling licenses, we decided that we probably need to change our model and we just need to release Pony under Apache 2 license.

00:24:34.720 --> 00:24:46.360
And think about the possibility to monetize our editor because it really can be a tool which allows people to develop applications faster.

00:24:46.360 --> 00:24:50.280
And we use the same model as GitHub.

00:24:50.640 --> 00:24:57.780
So if you would like to share your data schema with everybody, make it public, you can use it for free.

00:24:57.780 --> 00:25:03.380
And if you would like to have a private data schema, then we'll ask to pay some money.

00:25:03.380 --> 00:25:04.760
Yeah, I think that's a great model.

00:25:04.760 --> 00:25:06.260
And we'll definitely talk about it.

00:25:06.260 --> 00:25:08.680
That's at editor.ponyorm.com.

00:25:09.400 --> 00:25:10.500
Yeah, it's very cool.

00:25:10.500 --> 00:25:28.120
This portion of Talk Python To Me has been brought to you by Rollbar.

00:25:28.440 --> 00:25:31.640
One of the frustrating things about being a developer is dealing with errors.

00:25:31.640 --> 00:25:39.840
Ah, relying on users to report errors, digging through log files, trying to debug issues, or a million alerts just flooding your inbox and ruining your day.

00:25:39.840 --> 00:25:47.040
With Rollbar's full stack error monitoring, you'll get the context, insights, and control that you need to find and fix bugs faster.

00:25:47.040 --> 00:25:48.760
It's easy to install.

00:25:48.760 --> 00:25:53.000
You can start tracking production errors and deployments in eight minutes or even less.

00:25:53.600 --> 00:26:02.380
Rollbar works with all the major languages and frameworks, including the Python ones, such as Django, Flask, Pyramid, as well as Ruby, JavaScript, Node, iOS, and Android.

00:26:02.380 --> 00:26:11.580
You can integrate Rollbar into your existing workflow, send error alerts to Slack or HipChat, or even automatically create issues in Jira, Pivotal Tracker, and a whole bunch more.

00:26:11.580 --> 00:26:14.940
Rollbar has put together a special offer for Talk Python To Me listeners.

00:26:14.940 --> 00:26:20.620
Visit rollbar.com slash talkpython to me, sign up, and get the bootstrap plan free for 90 days.

00:26:20.960 --> 00:26:23.700
That's 300,000 errors tracked all for free.

00:26:23.700 --> 00:26:27.400
But hey, just between you and me, I really hope you don't encounter that many errors.

00:26:27.400 --> 00:26:33.400
Loved by developers at awesome companies like Heroku, Twilio, Kayak, Instacart, Zendesk, Twitch, and more.

00:26:33.400 --> 00:26:35.020
Give Rollbar a try today.

00:26:35.020 --> 00:26:37.640
Go to rollbar.com slash talkpython to me.

00:26:46.120 --> 00:26:52.760
Let's focus for a moment on what I think are really getting to the Pythonic concepts.

00:26:52.760 --> 00:27:00.160
What we talked about so far with the way you work with Pony is it's very nice, but it's not super unique.

00:27:00.160 --> 00:27:03.260
And it's just like a nicer version of what I feel like the other ones are doing.

00:27:03.400 --> 00:27:10.980
But then you get to things like working with context managers and decorators and all sorts of really nice stuff.

00:27:10.980 --> 00:27:13.800
Tell us, how do we like insert data?

00:27:13.800 --> 00:27:19.060
Or how do I get like a database connection and commit it and go through like that whole set of steps there?

00:27:19.180 --> 00:27:24.880
Well, when you bind entities to the database, the next step, you need to generate mapping.

00:27:24.880 --> 00:27:34.180
And this way we just connect objects in the program entities to the database tables.

00:27:34.180 --> 00:27:38.420
And then you can start working with the database.

00:27:38.420 --> 00:27:43.240
You can select entity objects or create new objects.

00:27:43.240 --> 00:27:52.140
And all that interconnection should be done within the database session because it is a transaction, right?

00:27:52.140 --> 00:27:53.780
Right, this whole unit of work thing, right?

00:27:53.780 --> 00:27:55.060
Yeah, unit of work, exactly.

00:27:55.060 --> 00:28:00.960
So you need to either create a function and decorate it with DB session.

00:28:00.960 --> 00:28:09.360
Or you need to use the context manager and work with the database within this context manager.

00:28:09.360 --> 00:28:12.080
Yeah, so let's focus on that for a sec because I think that's great.

00:28:12.080 --> 00:28:25.500
So if I want to make a bunch of CRUD operations, inserts, updates, deletes, and so on, one way to do that is write a function that changes the data, creates objects, it updates existing ones.

00:28:25.500 --> 00:28:30.300
And all I have to do is put a decorator at DB session on that method.

00:28:30.300 --> 00:28:36.220
And it will handle both the positive outcome and the negative outcome.

00:28:36.220 --> 00:28:43.580
So if that method runs to completion without errors, without exceptions, it will commit the transaction.

00:28:43.580 --> 00:28:49.800
But if for some reason there's an exception in there, it will roll back the transaction just by virtue of having the decorator, right?

00:28:49.800 --> 00:28:50.360
Exactly.

00:28:51.180 --> 00:28:59.820
So when you wrap your code, which works with entities with DB session, it actually does the following.

00:28:59.820 --> 00:29:07.060
When you start working with the database, it doesn't start the transaction from the first moment.

00:29:07.060 --> 00:29:12.820
Because if it is just read, you don't need to open the transaction.

00:29:12.820 --> 00:29:17.480
You can read from the database without opening it.

00:29:17.480 --> 00:29:21.820
And when you start to change, the new transaction is created.

00:29:21.820 --> 00:29:31.760
And then when you leave this scope, if no exception happened, then Pony automatically will commit the changes to the database.

00:29:31.760 --> 00:29:36.540
If an exception happened, then it will be rolled back.

00:29:36.540 --> 00:29:40.580
And you can specify parameters to this decorator.

00:29:40.580 --> 00:29:48.180
For example, if you would like to retry several times, you can do that specifying parameters to the decorator.

00:29:48.520 --> 00:29:55.240
That might be helpful when you have more than one process working with the same table with the same row.

00:29:55.240 --> 00:29:59.880
And Pony has a concept of optimistic checking.

00:29:59.880 --> 00:30:05.680
So this way we avoid a situation when you can lose updates.

00:30:05.680 --> 00:30:14.640
When Pony saves something in the database, it actually adds checks that the attribute values keep the same.

00:30:15.260 --> 00:30:22.220
Because when you work with objects, Pony tracks which objects you read and which objects you write.

00:30:23.000 --> 00:30:32.700
So if you, for example, in your code, read an attribute and then do something and save this object into the database,

00:30:32.700 --> 00:30:38.440
Pony will make sure that attributes that you read keep the same.

00:30:38.440 --> 00:30:43.900
Because if it don't, it means that some other process changed the database.

00:30:43.900 --> 00:30:46.560
And in this case, it cannot be saved in the database.

00:30:46.560 --> 00:30:52.540
Yeah, this is very common in the sort of disconnected unit of work styles of ORMs.

00:30:52.540 --> 00:30:54.100
But I really like this model.

00:30:54.100 --> 00:30:58.820
I mean, the alternative is pessimistic concurrency, which is to say, lock the database.

00:30:58.820 --> 00:31:02.320
Nobody can do a thing until we're done with this whole part, right?

00:31:02.320 --> 00:31:04.100
And everybody get in line.

00:31:04.100 --> 00:31:05.660
And I'm going to do a bunch of changes.

00:31:05.660 --> 00:31:11.280
And then you can go make your queries or other operations on the database and not see inconsistent data.

00:31:11.280 --> 00:31:13.840
And that's great.

00:31:13.840 --> 00:31:17.580
But it also kills concurrency and all sorts of things.

00:31:17.580 --> 00:31:23.400
With this model, the optimistic concurrency, it's like, well, probably nobody changed this record also.

00:31:23.400 --> 00:31:25.140
So it'll just do all the work.

00:31:25.200 --> 00:31:32.420
And then it'll say more or less something to the effect of, update person with ID this where the name is the old name.

00:31:32.420 --> 00:31:33.840
Set the name to the new name.

00:31:33.840 --> 00:31:34.980
Something like that, right?

00:31:34.980 --> 00:31:43.140
So the goal of Pony is provide consistent API and ability to work with the database,

00:31:43.140 --> 00:31:49.020
even for people who don't know much about transactions and lost updates.

00:31:49.880 --> 00:31:56.320
So we would like Pony to provide such an easy way to work with the data reliably.

00:31:56.320 --> 00:31:56.760
Yeah.

00:31:56.760 --> 00:31:58.900
And I think the retrying thing is really interesting.

00:31:58.900 --> 00:32:00.640
A really interesting addition there.

00:32:00.640 --> 00:32:05.940
Sometimes you don't want to make an entire method, basically a transaction in a sense.

00:32:05.940 --> 00:32:10.380
So you can use another Pythonic concept of context managers, right?

00:32:10.380 --> 00:32:13.860
So you can just say with DB session, do you work in that little suite?

00:32:13.860 --> 00:32:16.720
And then when you're out of there, it follows the same rules.

00:32:16.720 --> 00:32:18.060
No exceptions, commit.

00:32:18.060 --> 00:32:19.520
Exception, rollback, right?

00:32:19.680 --> 00:32:19.900
Right.

00:32:19.900 --> 00:32:26.640
And at the same time, this concept of optimistic checking, it works by default in Pony.

00:32:26.640 --> 00:32:33.840
But if you need to log the database, do for update query, you can do that too.

00:32:33.840 --> 00:32:40.780
There's a method for entity has a method for update, and a query has such a method for update.

00:32:40.780 --> 00:32:44.640
So this way you can log the database if you need.

00:32:44.640 --> 00:32:45.660
Right.

00:32:45.660 --> 00:32:46.020
Okay.

00:32:46.020 --> 00:32:46.560
Very cool.

00:32:46.560 --> 00:32:49.340
So the next thing, once you have data in the database, of course,

00:32:49.380 --> 00:32:50.220
you want to write a query.

00:32:50.220 --> 00:32:55.140
And this is where, this is what got my attention in Pony in the first place, is the way that

00:32:55.140 --> 00:33:01.820
I would, like, say, do a query on, like, a bunch of people we inserted to the database

00:33:01.820 --> 00:33:07.720
at the person class would be to write a generator that would do the in-memory query.

00:33:08.020 --> 00:33:12.360
So you'd say something like, select P for P in person if P dot age is greater than 20.

00:33:12.360 --> 00:33:13.980
And, like, that's literally what you write.

00:33:13.980 --> 00:33:14.420
Yeah?

00:33:14.420 --> 00:33:14.860
Yeah.

00:33:14.860 --> 00:33:21.040
You write this generator and pass it as an argument to the select function.

00:33:21.760 --> 00:33:22.600
And what Pony does?

00:33:22.600 --> 00:33:26.580
And what Pony does, it gets the bytecode of the generator.

00:33:26.580 --> 00:33:31.300
It decompiles it in order to extract the abstract syntax tree.

00:33:31.300 --> 00:33:36.540
And then it translates this abstract syntax tree into SQL.

00:33:37.700 --> 00:33:42.200
And made a presentation on the EuroPython in 2014.

00:33:42.200 --> 00:33:51.520
And it is available on YouTube where I explain the whole process, how we actually do this translation.

00:33:52.360 --> 00:33:59.780
Because before, a lot of people actually asking if this translation is fast enough.

00:33:59.780 --> 00:34:04.680
And I should tell that the whole thing works really fast.

00:34:04.680 --> 00:34:09.480
And the thing is that you need to translate each generator only once.

00:34:09.480 --> 00:34:15.120
In the whole program, you need to translate the generator bytecode only once.

00:34:15.120 --> 00:34:16.940
And then it will be cached.

00:34:16.940 --> 00:34:21.720
And the result of the translation to SQL will be cached as well.

00:34:22.340 --> 00:34:30.440
And after that, we just have the SQL query where we just put parameters and send it to the database.

00:34:30.440 --> 00:34:31.860
That is really awesome.

00:34:31.860 --> 00:34:34.200
I'm definitely going to link to your 2014 talk.

00:34:34.200 --> 00:34:36.160
You could also do, like, projections.

00:34:36.160 --> 00:34:41.920
So, like, in a generator expression, I could say p.name, p.age for da-da-da-da.

00:34:41.920 --> 00:34:46.940
You support basically doing projections at the database level in the same manner, right?

00:34:46.940 --> 00:34:47.600
Right.

00:34:47.600 --> 00:34:53.800
So, basically, you don't even need to think in terms of tables.

00:34:53.800 --> 00:34:55.420
You just work with objects.

00:34:56.320 --> 00:35:02.200
And you can select a whole object or you can select a specific attribute.

00:35:02.200 --> 00:35:05.420
Or you can even do aggregation.

00:35:05.420 --> 00:35:07.520
So, you select a tuple.

00:35:07.520 --> 00:35:10.980
For example, you select p.name.

00:35:10.980 --> 00:35:13.520
And then, for example, if we have some...

00:35:13.520 --> 00:35:15.460
Let me give you this example.

00:35:15.680 --> 00:35:18.560
For example, you work with a customer.

00:35:18.560 --> 00:35:26.380
And this customer has some orders which has the attribute total amount.

00:35:26.780 --> 00:35:40.440
So, you can do aggregation and return from this query a tuple where you have the customer name and then aggregated amount of his or her orders.

00:35:40.440 --> 00:35:41.520
That's really cool.

00:35:41.520 --> 00:35:43.560
Do you have some good examples of that on your docs?

00:35:43.560 --> 00:35:43.880
Yeah.

00:35:43.880 --> 00:35:44.480
Okay.

00:35:44.480 --> 00:35:45.340
I'll be sure to link to them.

00:35:45.340 --> 00:35:45.480
Yeah.

00:35:45.480 --> 00:35:45.980
Send me the link.

00:35:46.560 --> 00:35:55.980
And finally, if for some reason this syntax doesn't work for you, you're just like, you know, I just need to write a SQL query and just have something happen.

00:35:55.980 --> 00:35:57.520
You can do that as well.

00:35:57.520 --> 00:36:05.340
And so, you could just go to your entity which represents the table and just say select by SQL and give it some kind of SQL statement.

00:36:05.340 --> 00:36:16.440
You can write a row SQL, but what is more interesting is that you can insert a row parts of SQL query into a generator.

00:36:16.440 --> 00:36:20.540
You know, we have such a function, row SQL.

00:36:20.540 --> 00:36:27.980
And, for example, there is a function in the database which is not supported in Python, for example.

00:36:28.120 --> 00:36:37.200
Then you can insert this piece of row SQL into a declarative query written in the form of a generator.

00:36:37.200 --> 00:36:38.560
That is really awesome.

00:36:38.560 --> 00:36:48.080
And I also like how you automatically capture in your SQL text local variables as names.

00:36:48.080 --> 00:36:54.700
So, like, if I had X defined locally, in my SQL statement, I could say $X and you would translate that to a parameter, right?

00:36:54.700 --> 00:36:55.180
Yeah.

00:36:55.460 --> 00:36:59.420
And one second, let me send you the link for a row SQL.

00:36:59.420 --> 00:37:00.040
Oh, yeah.

00:37:00.040 --> 00:37:00.940
That's really amazing.

00:37:00.940 --> 00:37:11.020
So, you can just say raw SQL as part of either a Lambda or a generator expression and it just, it's going to execute on the database, right?

00:37:11.020 --> 00:37:11.540
Exactly.

00:37:11.540 --> 00:37:17.540
So, if you insert this part of a row SQL into the translated query.

00:37:17.540 --> 00:37:22.060
Now, one thing that's interesting is you have both Lambda expressions and generator expressions.

00:37:22.060 --> 00:37:22.600
Right.

00:37:23.060 --> 00:37:26.540
When do I use, and I can pass those as the select clause.

00:37:26.540 --> 00:37:28.160
So, when do I use which?

00:37:28.160 --> 00:37:35.040
If you would like to get an object as the result, you can use Lambda or generator.

00:37:35.040 --> 00:37:40.180
So, they will actually be translated into the same SQL query.

00:37:40.180 --> 00:37:57.720
But if you would like to aggregate the aggregation or return just a tuple of attribute names, then in this case, you use a generator because it allows you to put any expression in the beginning of the generator.

00:37:57.720 --> 00:37:58.580
Right.

00:37:58.660 --> 00:38:03.400
And it will be returned as a list of such tuples, for example.

00:38:03.400 --> 00:38:03.700
Yeah.

00:38:03.700 --> 00:38:06.300
I really love that aspect of Pony.

00:38:06.300 --> 00:38:07.320
That's super cool.

00:38:07.320 --> 00:38:17.380
So, let's talk about parameters because it's super important for the safety of your app that you don't write just straight up raw SQL with concatenated strings, right?

00:38:17.780 --> 00:38:20.740
Like, if anybody has a doubt, just Google little Bobby tables.

00:38:20.740 --> 00:38:23.440
So, the parameters here are really great.

00:38:23.440 --> 00:38:24.720
Like, tell us about that.

00:38:24.720 --> 00:38:36.580
Pony allows you to avoid SQL injections absolutely because all the parameters that we pass into the SQL query, they are passed as database parameters.

00:38:36.580 --> 00:38:40.740
So, this way, there is no way to get a SQL injection.

00:38:40.740 --> 00:38:47.820
And also, Pony allows you to pass not only parameters but expressions as well.

00:38:47.820 --> 00:38:52.080
So, you can find that part described in the documentation.

00:38:52.500 --> 00:39:00.100
When you pass the parameter, you can specify the whole expression inside the generator query.

00:39:00.100 --> 00:39:02.600
That's really great that you can pass expressions as well.

00:39:02.600 --> 00:39:09.080
I think there's always tradeoffs when you use something, some kind of ORM versus just writing raw SQL entirely.

00:39:09.080 --> 00:39:20.580
I would, personally, the safety from SQL injection attacks, the fact that you might forget to use a parameter somewhere, almost alone makes it worth using ORMs.

00:39:20.740 --> 00:39:23.200
Not to mention all the cool benefits of everything else.

00:39:23.200 --> 00:39:29.260
So, yeah, I think it's really great that you have all these levels of safety, especially for web apps.

00:39:29.260 --> 00:39:29.900
Yeah.

00:39:29.900 --> 00:39:31.260
So, let's talk about the team.

00:39:31.620 --> 00:39:35.480
You talked about your co-founder just a bit, but maybe mention him again.

00:39:35.480 --> 00:39:37.840
And how many people are working on the project now?

00:39:37.840 --> 00:39:39.580
Currently, we have four people.

00:39:39.580 --> 00:39:42.280
So, Alexander Kozlovsky is my co-founder.

00:39:42.280 --> 00:39:45.440
And we started to work with him together.

00:39:45.440 --> 00:39:53.300
And at some point, I decided to leave my job and concentrate on Pony full-time.

00:39:53.300 --> 00:39:54.560
Congratulations on that.

00:39:54.560 --> 00:39:55.020
That's awesome.

00:39:55.180 --> 00:39:55.800
Yeah, thank you.

00:39:55.800 --> 00:39:59.260
Although, we found another project later.

00:39:59.260 --> 00:40:02.320
So, currently, we work on Pony.

00:40:02.320 --> 00:40:04.160
We have four people.

00:40:04.160 --> 00:40:06.280
We have two more developers.

00:40:06.280 --> 00:40:10.420
So, one of them works on backend and another on frontend.

00:40:10.420 --> 00:40:15.080
So, his role is to help us build our editor.

00:40:15.080 --> 00:40:17.300
We have big plans on that.

00:40:18.100 --> 00:40:23.440
And currently, we actually, yeah, we work on the editor as well.

00:40:23.440 --> 00:40:23.880
Nice.

00:40:23.880 --> 00:40:24.540
Yeah.

00:40:24.540 --> 00:40:26.400
So, tell us where are you going?

00:40:26.400 --> 00:40:27.520
What features are you adding?

00:40:27.520 --> 00:40:33.500
Currently, you can use the editor in order to create entity relationship diagram.

00:40:33.500 --> 00:40:40.700
And then get either a Python classes or SQL create table statements.

00:40:41.660 --> 00:40:49.120
And this is actually used a lot by users who actually don't know anything about Pony.

00:40:49.120 --> 00:40:52.400
And when I write them that, do you use Pony?

00:40:52.400 --> 00:40:57.880
Why not you just start opening the tab with Python classes?

00:40:57.880 --> 00:41:01.700
They actually, often, they don't know a thing about Pony.

00:41:01.700 --> 00:41:08.240
And when they discover this possibility, they love this feature and start using Pony as well.

00:41:08.240 --> 00:41:09.200
Yeah, that's great.

00:41:09.200 --> 00:41:09.420
Yeah.

00:41:09.420 --> 00:41:11.060
So, let's talk about your editor a little bit.

00:41:11.060 --> 00:41:12.380
So, I really like it.

00:41:12.380 --> 00:41:14.560
Like I said, editor.ponyorm.com.

00:41:14.560 --> 00:41:20.400
And the idea is it's basically a database diagram development tool, right?

00:41:20.400 --> 00:41:21.680
So, you can see your tables.

00:41:21.680 --> 00:41:27.000
You can see the relationships and so on, which all that is really cool.

00:41:27.000 --> 00:41:30.440
And I can, like, add a new entity.

00:41:30.440 --> 00:41:32.580
And it gives you a whole nice designer.

00:41:32.580 --> 00:41:37.080
It shows you a bunch of stuff that maybe you didn't realize was something that you could model,

00:41:37.080 --> 00:41:40.340
like the volatility of attributes or things like this.

00:41:40.460 --> 00:41:46.400
But then once you get your model built together, you can actually go and say, show me the Python code.

00:41:46.400 --> 00:41:53.400
Yeah, show me the Python code.

00:41:53.400 --> 00:42:00.780
For the various databases and so on, you know, you can create this.

00:42:00.780 --> 00:42:11.460
So, you can create a tool that you can create a tool that allows them to do the whole cycle of development.

00:42:12.000 --> 00:42:13.000
So, when they can create a diagram.

00:42:13.000 --> 00:42:18.500
So, when they can create a diagram and then get the Python code and work on the project.

00:42:18.500 --> 00:42:26.980
And when they need to change something, they can just change it in the editor and get their migration applied to the database.

00:42:27.440 --> 00:42:31.440
And keep those, the log of the changes in the editor.

00:42:31.440 --> 00:42:32.000
Nice.

00:42:32.000 --> 00:42:32.560
Yeah, okay.

00:42:32.560 --> 00:42:34.740
So, that's really neat.

00:42:34.740 --> 00:42:36.980
That brings us to migrations a little bit.

00:42:36.980 --> 00:42:38.360
What's the story of migrations there?

00:42:38.360 --> 00:42:43.640
This point is the feature which is most asked.

00:42:44.040 --> 00:42:50.660
And at this point, we are working on migrations and we developed the prototype.

00:42:50.660 --> 00:42:53.640
And it works great.

00:42:53.640 --> 00:43:02.840
But what we would like to add, an ability to write comments inside the migration file the same way as in Django.

00:43:03.200 --> 00:43:14.400
So, when you just write operations like add attribute or add relationship, I believe that it will be released within the following month.

00:43:14.400 --> 00:43:17.420
But it is not that fast.

00:43:17.420 --> 00:43:22.640
The development of migrations took longer than we initially suggested.

00:43:22.640 --> 00:43:24.840
Yeah, it seems like it might take a while.

00:43:24.840 --> 00:43:26.540
It's a non-trivial thing.

00:43:26.540 --> 00:43:27.380
That's right.

00:43:27.380 --> 00:43:30.440
But we are very close to the release at this point.

00:43:30.440 --> 00:43:30.820
Nice.

00:43:30.940 --> 00:43:33.300
Yeah, what are you doing after you get the migrations done?

00:43:33.300 --> 00:43:37.420
Some time ago, we started to work on a project which is called Fine Art Biblio.

00:43:37.420 --> 00:43:40.140
So, it is a Miami-based company.

00:43:40.140 --> 00:43:44.900
And the goal is to provide Wikipedia for modern art.

00:43:44.900 --> 00:43:47.520
I formed a team for this project.

00:43:47.520 --> 00:43:50.500
And from day one, we started to use Pony.

00:43:50.500 --> 00:44:01.100
It was actually our goal to find a company where we can use Pony in order to build the back end and see how we can make it better.

00:44:01.100 --> 00:44:12.240
And when we were working on this project, we found that when we need to build a front end, we actually need to have the same models as the front end.

00:44:12.460 --> 00:44:23.320
And we thought, why not to provide a way to have the same identity map, the same models as the front end.

00:44:23.320 --> 00:44:26.500
And this way was Pony.js.

00:44:26.500 --> 00:44:28.580
This way, Pony.js appeared.

00:44:28.640 --> 00:44:33.920
So, Pony.js is a don to Pony, which is not released yet.

00:44:33.920 --> 00:44:37.160
Why, I will tell a little bit later.

00:44:37.940 --> 00:44:43.820
And this way, you can get the objects which are extracted in the back end.

00:44:43.820 --> 00:44:52.000
You can have the same graph of connected objects at the front end and work with them in JavaScript.

00:44:52.000 --> 00:44:52.480
Nice.

00:44:52.480 --> 00:45:00.560
So, I can just basically expose my models from my back end as some kind of service that Pony.js can consume.

00:45:00.560 --> 00:45:02.080
And then they're like replicated over?

00:45:02.080 --> 00:45:03.140
Or how does that work?

00:45:03.280 --> 00:45:09.480
When you extracted objects from the database, then you call the to.json method.

00:45:09.480 --> 00:45:15.900
And it returns a set of objects which will be sent to the front end.

00:45:15.900 --> 00:45:29.000
And the front end, we have a library, Pony.js, which puts it into an identity map and allows you to work with objects the same way you do it on the back end.

00:45:29.140 --> 00:45:31.620
So, you can traverse attributes.

00:45:31.620 --> 00:45:34.100
You can traverse relationships.

00:45:34.100 --> 00:45:38.860
You can create new objects and send them back to the back end.

00:45:38.860 --> 00:45:39.580
That's cool.

00:45:39.580 --> 00:45:48.700
And for allowing this, for making this work, we created a layer of permissions and security.

00:45:48.700 --> 00:45:55.980
So, it is also a declarative language which allows you to tell which operations are allowed.

00:45:55.980 --> 00:45:58.940
Create, delete, update, or modify.

00:45:59.400 --> 00:46:06.840
But when we were working on this project, we found that Facebook released GraphQL.

00:46:06.840 --> 00:46:12.560
And we thought that probably it is the same thing that we are working on.

00:46:12.560 --> 00:46:16.360
And we decided actually to try GraphQL.

00:46:17.020 --> 00:46:22.640
And by this time, we had one more team member joined to our company.

00:46:22.640 --> 00:46:26.560
And he developed GraphQL server.

00:46:26.560 --> 00:46:31.720
And now we have actually three ways to work with the front end.

00:46:31.720 --> 00:46:40.960
And after we release migrations, we believe that integration with the front end actually will be our major focus.

00:46:41.080 --> 00:46:44.000
Yeah, you have your back end stuff pretty much dialed in.

00:46:44.000 --> 00:46:46.540
So, extending that seems like a great idea.

00:47:00.980 --> 00:47:05.500
This portion of Talk Python To Me is brought to you by GoCD from ThoughtWorks.

00:47:05.500 --> 00:47:10.160
GoCD is the on-premise, open-source, continuous delivery server.

00:47:10.160 --> 00:47:16.960
With GoCD's comprehensive pipeline and model, you can model complex workflows for multiple teams with ease.

00:47:16.960 --> 00:47:22.780
And GoCD's value stream map lets you track changes from commit to deployment at a glance.

00:47:22.780 --> 00:47:27.780
GoCD's real power is in the visibility it provides over your end-to-end workflow.

00:47:27.780 --> 00:47:32.760
You get complete control of and visibility into your deployments across multiple teams.

00:47:32.760 --> 00:47:37.240
Say goodbye to release day panic and hello to consistent, predictable deliveries.

00:47:37.240 --> 00:47:42.140
Commercial support and enterprise add-ons, including disaster recovery, are available.

00:47:42.140 --> 00:47:48.100
To learn more about GoCD, visit talkpython.fm/gocd for a free download.

00:47:48.100 --> 00:47:51.400
That's talkpython.fm/gocd.

00:47:51.400 --> 00:47:52.500
Check them out.

00:47:52.500 --> 00:47:53.500
It helps support the show.

00:47:53.500 --> 00:48:02.740
So, your docs are in Python 2.

00:48:02.740 --> 00:48:06.340
I want to encourage you to write them in Python 3 and tell a story.

00:48:06.340 --> 00:48:12.660
So, when people were looking at the adoption of Python 3, maybe a year ago or something like this,

00:48:12.660 --> 00:48:17.920
and I think around that time, Django switched its documentation to Python 3.

00:48:18.540 --> 00:48:19.600
They didn't do anything else.

00:48:19.600 --> 00:48:21.020
They just said, look, Python 3 here.

00:48:21.020 --> 00:48:22.680
This is the way you do it in Python 3.

00:48:22.680 --> 00:48:24.180
And, oh, it also supports Python 2.

00:48:24.180 --> 00:48:33.560
And the usage of Python 3 on PyPI went up significantly, like some number of percent total because of that.

00:48:33.560 --> 00:48:39.100
But my real question is, does it support Python 3 as well as Python 2?

00:48:39.100 --> 00:48:41.580
What's the story around on the various versions?

00:48:41.580 --> 00:48:42.380
Yes, it does.

00:48:42.380 --> 00:48:43.460
Nice.

00:48:43.460 --> 00:48:43.900
Yeah.

00:48:43.900 --> 00:48:48.680
So, all the stuff that I've done with it worked totally fine, and I was playing with it in Python 3.

00:48:48.680 --> 00:48:49.640
So, that's great.

00:48:49.640 --> 00:48:57.880
So, I'm really fascinated by people working on successful open source projects that have businesses around them.

00:48:57.880 --> 00:49:05.020
And so, can you talk just really briefly about your project and the editor and the business model around it?

00:49:05.020 --> 00:49:14.720
We think that the editor could be helpful for startup companies and for companies which develop new projects.

00:49:15.260 --> 00:49:29.660
Those people who we were talking to who would like to use Pony in their projects, we found that what they like in Pony is simplicity and that Pony allows them to save resources.

00:49:29.660 --> 00:49:31.640
So, they can start fast.

00:49:31.640 --> 00:49:35.660
They don't need dedicated backend engineer sometimes.

00:49:35.660 --> 00:49:48.400
And they just can easily return to the project which was developed like a year ago and do some changes without actually looking through the manuals.

00:49:48.400 --> 00:49:58.660
Because the query language is really simple and it allows to maintain projects with less resources.

00:49:59.600 --> 00:50:09.800
We think that for such people, for such companies, having an editor would help them to build prototypes and to work on applications even faster.

00:50:09.800 --> 00:50:17.680
Especially if they would be able to work on the same data schema together.

00:50:17.680 --> 00:50:21.860
And this is one of the features we would like to add to our editor.

00:50:22.460 --> 00:50:26.020
So, the idea is that it is software as a service.

00:50:26.020 --> 00:50:33.520
And if you would like to create a diagram and share it with everyone, it is free.

00:50:33.660 --> 00:50:43.100
And if you would like to keep it as a closed source diagram, then there is some price for this.

00:50:43.100 --> 00:50:47.360
And it depends on how many diagrams you would like to have.

00:50:47.360 --> 00:50:47.620
Sure.

00:50:47.620 --> 00:50:50.160
You know, one thing I think is really interesting about this.

00:50:50.160 --> 00:50:57.020
You talk about people getting started more quickly and helping new companies or new applications get up to speed.

00:50:57.240 --> 00:50:59.700
You have an explore section here.

00:50:59.700 --> 00:51:05.100
So, I can drop in and find things like you've got a corporate directory already modeled.

00:51:05.100 --> 00:51:09.360
And you've got an e-commerce store modeled and a university modeled and things like that.

00:51:09.360 --> 00:51:13.360
So, if I know that there's something in your explore area.

00:51:13.360 --> 00:51:16.340
Some of these are created by you guys, but many of them are by others.

00:51:16.340 --> 00:51:19.260
And I'm like, well, how exactly would I model this?

00:51:19.260 --> 00:51:21.440
Let me just look and see what other people have done.

00:51:21.440 --> 00:51:21.680
Right?

00:51:21.680 --> 00:51:24.340
I could go and just start from there, right?

00:51:24.340 --> 00:51:25.020
And copy that.

00:51:25.020 --> 00:51:25.580
Yeah, exactly.

00:51:25.580 --> 00:51:37.840
And maybe at some point, we will add an ability to deploy the schema to a cloud database and write logic right there.

00:51:37.840 --> 00:51:38.840
Yeah, that's pretty interesting.

00:51:38.840 --> 00:51:42.900
Is there a way to take and reverse the thing?

00:51:43.060 --> 00:51:46.560
So, I've got the diagram which generates my Python.

00:51:46.560 --> 00:51:55.760
Could I take my code that I've been working on for six months after starting with one of these and throw the Python in and get the diagram out?

00:51:55.760 --> 00:51:57.100
Probably we should add that.

00:51:57.100 --> 00:52:03.240
But at this point, the most people are asking about a reflection tool for the database.

00:52:03.240 --> 00:52:12.540
So, when you can just get the log of the database, create table statements, and create a diagram based on that.

00:52:12.540 --> 00:52:13.380
Yeah, that makes sense.

00:52:13.380 --> 00:52:20.400
Which, I guess, is probably the most important one is you want to be exactly like your database and give me the Python classes to make that happen, right?

00:52:20.400 --> 00:52:20.820
Right.

00:52:20.820 --> 00:52:29.040
So, someone would like to work using Pony with a database, and they just don't want to create those classes or a diagram.

00:52:29.040 --> 00:52:33.600
Yeah, if you've got a thousand tables, you probably don't want to spend time trying to model them again.

00:52:33.600 --> 00:52:36.260
Just push the button and have that pop out, right?

00:52:36.260 --> 00:52:36.660
That's cool.

00:52:36.660 --> 00:52:37.420
All right.

00:52:37.420 --> 00:52:39.260
Well, we're getting near the end of the show.

00:52:39.260 --> 00:52:40.920
This has been really interesting.

00:52:40.920 --> 00:52:44.980
I'm really fascinated, especially with the Pythonic style of Pony.

00:52:44.980 --> 00:52:48.460
So, thanks for telling us all about it and giving us the backstory.

00:52:48.460 --> 00:52:49.060
It's great.

00:52:49.060 --> 00:52:50.660
Thank you, Michael, for having me.

00:52:50.660 --> 00:52:51.340
Yeah, you bet.

00:52:51.340 --> 00:52:54.600
So, before I let you go, though, I have a couple of questions for you.

00:52:54.600 --> 00:52:58.520
There's over 90,000 packages on PyPI these days.

00:52:59.020 --> 00:53:01.520
And you probably come across some that not everybody knows about.

00:53:01.520 --> 00:53:03.420
What one would you like to recommend to audience?

00:53:03.420 --> 00:53:04.940
Well, I love Flask.

00:53:04.940 --> 00:53:10.120
Flask is definitely nice and great for building apps, especially for building APIs, I think.

00:53:10.120 --> 00:53:10.580
Right.

00:53:10.580 --> 00:53:18.020
We use it in our projects, and it's simple, and you can develop very fast using Flask.

00:53:18.020 --> 00:53:19.140
So, that's why I like it.

00:53:19.140 --> 00:53:19.400
All right.

00:53:19.400 --> 00:53:19.800
Flask.

00:53:19.800 --> 00:53:20.600
Great recommendation.

00:53:20.600 --> 00:53:23.860
And if you're going to write some Python code, what editor do you open up?

00:53:23.860 --> 00:53:24.400
PyCharm.

00:53:24.400 --> 00:53:25.300
Nice.

00:53:26.060 --> 00:53:26.220
Yeah.

00:53:26.220 --> 00:53:29.520
A lot of the PyCharm team is based in St. Petersburg, along with you.

00:53:29.520 --> 00:53:29.940
Yeah.

00:53:29.940 --> 00:53:31.480
So, do you know some of the guys there?

00:53:31.480 --> 00:53:32.240
Yeah, I do.

00:53:32.240 --> 00:53:37.540
Actually, we met with them, and we were asking them to add support for Pony.

00:53:38.460 --> 00:53:44.640
And we agree that when enough people will be asking about it, they will start working on

00:53:44.640 --> 00:53:44.800
this.

00:53:44.800 --> 00:53:45.440
All right.

00:53:45.440 --> 00:53:47.380
Well, maybe this show will give them a little nudge, huh?

00:53:47.380 --> 00:53:47.920
That's cool.

00:53:47.920 --> 00:53:49.940
Any final call to actions for everyone?

00:53:49.940 --> 00:53:52.100
Like, how do they get started with Pony and your project?

00:53:52.400 --> 00:53:56.020
Please go to pony.rm.com and read the documentation.

00:53:56.020 --> 00:53:58.060
Try Pony and give us feedback.

00:53:58.060 --> 00:54:07.580
We have a Telegram group where people can discuss Pony features and ask questions or stack overflow.

00:54:07.580 --> 00:54:13.460
And please give us some feedback so that we can make Pony even better.

00:54:13.460 --> 00:54:14.100
All right, Alexei.

00:54:14.100 --> 00:54:15.640
Thank you so much for being on the show.

00:54:15.640 --> 00:54:16.680
It's been fun to talk to you.

00:54:16.680 --> 00:54:17.400
Thank you, Michael.

00:54:17.400 --> 00:54:17.940
It was a pleasure.

00:54:17.940 --> 00:54:18.280
Yeah.

00:54:18.280 --> 00:54:18.520
Bye.

00:54:18.520 --> 00:54:22.700
This has been another episode of Talk Python To Me.

00:54:22.700 --> 00:54:25.340
Today's guest has been Alexei Milashkovic.

00:54:25.340 --> 00:54:28.560
And this episode has been sponsored by Rollbar and GoCD.

00:54:28.560 --> 00:54:30.520
Thank you both for supporting the show.

00:54:30.520 --> 00:54:33.360
Rollbar takes the pain out of errors.

00:54:33.360 --> 00:54:38.440
They give you the context and insight you need to quickly locate and fix errors that might have

00:54:38.440 --> 00:54:41.060
gone unnoticed until your users complain, of course.

00:54:41.060 --> 00:54:45.880
As Talk Python To Me listeners, track a ridiculous number of errors for free at

00:54:45.880 --> 00:54:48.220
rollbar.com slash Talk Python To Me.

00:54:48.220 --> 00:54:53.000
GoCD is the on-premise, open-source, continuous delivery server.

00:54:53.000 --> 00:54:57.120
Want to improve your deployment workflow but keep your code and builds in-house?

00:54:57.120 --> 00:55:03.500
Check out GoCD at talkpython.fm/gocd and take control over your process.

00:55:03.500 --> 00:55:06.060
Are you or a colleague trying to learn Python?

00:55:06.060 --> 00:55:10.720
Have you tried books and videos that just left you bored by covering topics point by point?

00:55:10.780 --> 00:55:16.740
Well, check out my online course, Python Jumpstart by Building 10 Apps at talkpython.fm/course

00:55:16.740 --> 00:55:19.340
to experience a more engaging way to learn Python.

00:55:19.340 --> 00:55:24.460
And if you're looking for something a little more advanced, try my Write Pythonic Code course at

00:55:24.460 --> 00:55:26.660
 talkpython.fm/pythonic.

00:55:27.240 --> 00:55:29.000
Be sure to subscribe to the show.

00:55:29.000 --> 00:55:31.200
Open your favorite podcatcher and search for Python.

00:55:31.200 --> 00:55:32.440
We should be right at the top.

00:55:32.900 --> 00:55:38.560
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct

00:55:38.560 --> 00:55:41.760
RSS feed at /rss on talkpython.fm.

00:55:42.120 --> 00:55:46.840
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.

00:55:46.840 --> 00:55:51.260
Corey just recently started selling his tracks on iTunes, so I recommend you check it out

00:55:51.260 --> 00:55:53.520
at talkpython.fm/music.

00:55:53.520 --> 00:55:57.960
You can browse his tracks he has for sale on iTunes and listen to the full-length version

00:55:57.960 --> 00:55:58.880
of the theme song.

00:55:58.880 --> 00:56:00.960
This is your host, Michael Kennedy.

00:56:00.960 --> 00:56:02.240
Thanks so much for listening.

00:56:02.240 --> 00:56:03.420
I really appreciate it.

00:56:03.420 --> 00:56:05.580
Smix, let's get out of here.

00:56:07.340 --> 00:56:08.060
with my voice.

00:56:08.060 --> 00:56:09.860
There's no norm that I can feel within.

00:56:09.860 --> 00:56:11.060
Haven't been sleeping.

00:56:11.060 --> 00:56:12.680
I've been using lots of rest.

00:56:12.680 --> 00:56:15.540
I'll pass the mic back to who rocked it best.

00:56:15.540 --> 00:56:27.100
Developers, Developers, Developers, Developers, Developers, Developers, Developers, Developers,

00:56:27.100 --> 00:56:27.600
.

00:56:27.600 --> 00:56:27.840
you

00:56:27.840 --> 00:56:28.340
you

