←back to thread

620 points tambourine_man | 3 comments | | HN request time: 0.65s | source
Show context
TekMol ◴[] No.43749608[source]
Will this allow neat SQL syntax like the following?

    city = 'London'
    min_age = 21
    # Find all users in London who are 21 or older:
    users = db.get(t'
        SELECT * FROM users
        WHERE city={city} AND age>{min_age}
    ')
If the db.get() function accepts a template, it should, right?

This would be the nicest way to use SQL I have seen yet.

replies(8): >>43749674 #>>43749734 #>>43749906 #>>43749926 #>>43749979 #>>43750037 #>>43751845 #>>43756963 #
jbaiter ◴[] No.43749674[source]
Thanks, I hate it. While it's nice syntactic sugar, the difference between an SQL injection vulnerability and a properly parametrized query is now a single letter that's easily missed
replies(5): >>43749680 #>>43749683 #>>43749690 #>>43749804 #>>43750217 #
JimDabell ◴[] No.43749804[source]
The t-string produces a Template object without a __str__() method. You can’t mistakenly use an f-string in its place. Either the code expects a string, in which case passing it a Template would blow it up, or the code expects a Template, in which case passing it a string would blow it up.
replies(5): >>43749994 #>>43750148 #>>43750347 #>>43751082 #>>43752420 #
crazygringo ◴[] No.43752420[source]
> or the code expects a Template, in which case passing it a string would blow it up.

That's where the problem is though -- in most cases it probably won't blow up.

Plenty of SQL queries don't have any parameters at all. You're just getting the number of rows in a table or something. A raw string is perfectly fine.

Will sqlite3 really disallow strings? Will it force you to use templates, even when the template doesn't contain any parameters?

You can argue it should, but that's not being very friendly with inputs, and will break backwards compatibility. Maybe if there's a flag you can set in the module to enable that strict behavior though, with the idea that in a decade it will become the default?

replies(1): >>43753002 #
WorldMaker ◴[] No.43753002[source]

    db.execute(t"Select Count(1) from someTable")
It's one extra letter to "force" for an unparameterized query over a "raw string". The t-string itself works just fine without parameters.

There's definitely a backwards compatibility hurdle of switching to a template-only API, but a template-only API doesn't look that much "less friendly" with inputs, when the only difference is a `t` before every string, regardless of number of parameters.

replies(1): >>43753116 #
crazygringo ◴[] No.43753116[source]
Sure, but it's just I don't have to do that anywhere else.

I never put an f in front of a string if I'm not putting variables within it.

And I'm generally used to Python inputs being liberal. I can usually pass a list if it expects a tuple; I can pass an int if it expects a float; often I can pass an item directly instead of a tuple with a single item. Regex functions take regular strings or regex strings, they don't force regex strings.

Being forced to use a single specific type of string in all cases is just very different from how Python has traditionally operated.

It's safer, I get that. But it's definitely less friendly, so I'll be curious to see how module maintainers decide to handle this.

replies(3): >>43753580 #>>43753590 #>>43756570 #
scott_w ◴[] No.43753580[source]
Er… that’s just not correct? Python can be more liberal but it’s not always. It depends entirely on the tooling. Libraries will take time to catch up but I can definitely see people creating libraries that enforce t-strings, even if they’re deconstructing them under the hood for legacy libraries.
replies(1): >>43753668 #
crazygringo ◴[] No.43753668[source]
What's not correct? Python inputs usually are liberal. I didn't say always.

Are you claiming it's traditionally common in Python to be strict with inputs, and that being liberal is the exception?

replies(1): >>43753770 #
scott_w ◴[] No.43753770[source]
That Python lets you blindly interchange different types for no good reason. It simply doesn’t.

Yes, it’s common for Python to be strict for inputs when the types are different. For example, try:

Decimal(‘3.0’) / 1.5

You’ll get an error and for good reason.

replies(1): >>43755136 #
crazygringo ◴[] No.43755136[source]
But... it usually does. For example, try:

    Decimal('3.0') / 2
It works fine. It doesn't work with a float, which is for good reason. That's the whole point -- its general philosophy is to be pretty liberal with types, except when there's a good reason not to be. Heck, you can even do dumb things like:

    4 + True
And get 5 back. If that's not "blindly interchanging different types for no good reason" then I don't know what is. You can even multiply your Decimal object by False and get an answer...

Or it's like my original example -- the Regex module isn't restricted to r-strings. It happily works with regular strings. Python's general philosophy is to handle input liberally. Even type hinting is an add-on. Now, it doesn't go as far as JavaScript in allowing e.g. "4"+1, but it's still awfully liberal. I just don't see how you can claim otherwise.

replies(2): >>43755478 #>>43759888 #
scott_w ◴[] No.43755478[source]
I know about Decimal/int mixing but that’s for a good reason: it’s fine to intermix here. But not for floats (precision issues). The bool/int mixing isn’t “good.” It’s a bad implementation detail that Python is stuck maintaining forever. I’m actually stunned that you think to use this as an example when I think I’d fire any programmer that did that in my team for gross negligence.

The reason it works is because Python functionally has no bool type. True and False are just integers with names. It’s stupid and shouldn’t work like that but it does for historic reasons.

Your example of regex makes no sense either. There is no difference between strings and r-strings. They’re literally the same thing to the interpreter, so how could the regex functions enforce you use r-strings? Maybe they should be different but, for historic reasons, they can’t be without Python 4.0.

replies(2): >>43756289 #>>43765307 #
1. crazygringo ◴[] No.43756289[source]
> I’m actually stunned that you think to use this as an example when I think I’d fire any programmer that did that in my team for gross negligence.

You seem to be having a different conversation than I am.

I'm just describing Python as it is. I'm not defending it. I know why you can add True to a number, or else I wouldn't have come up with the example. And I know perfectly well that r-strings are just strings. Python easily could have made them a distinct object, to force people from ever making backslash errors, and restricted Regex functions to them, but didn't.

My only point has been, "Pythonic" things tend to be pretty liberal in what they accept. Type hints aren't even enforced, when they exist at all. You seem to think it shouldn't be that way. Great! But regardless, claiming it's not that way -- that Python is somehow this strict language -- is just mischaracterizing it.

replies(1): >>43756569 #
2. scott_w ◴[] No.43756569[source]
> My only point has been, "Pythonic" things tend to be pretty liberal in what they accept

Being able to use a string as a string and an int as an int are not “pretty liberal in what they accept,” it’s just programming language theory 101! I think you’re mistaking duck typing for “liberal acceptance,” which are not the same thing. There’s always been an expectation that you should use compatible interfaces, even within the standard library. I’ve been bitten enough times by passing a generator in when a function expects a list, for example.

replies(1): >>43756785 #
3. crazygringo ◴[] No.43756785[source]
I'm not mistaking it at all. Yes, duck typing is very much liberal acceptance, but Python code tends to go much farther. I could give a million examples -- like how in Python's isinstance() the second argument can be a type or a tuple of types, or in sqlite3 that you can run queries on a connection or on a cursor, and don't even get me started on Matplotlib or Numpy. It's just idiomatic in Python to make things easy for the programmer by accepting multiple types when possible. If you don't recognize this as the common Python pattern, I literally don't know what else to tell you.