6 ms·
I really like the PHP approach of "one url, one file" by letting Apache handle the routing. I love to build a whole application by just putting a bunch of php f
by TekMol 4y ago
I really like the PHP approach of "one url, one file" by letting Apache handle the routing. I love to build a whole application by just putting a bunch of php files into a directory.
And I hate that in a typical Python+Django application, I have to restart the application to see changes I make.
But apart from that, Python is the nicer language. So I would like to do more web dev in Python. Most Python devs get red faces when you tell them that the PHP approach has benefits and you would prefer to go that route though.
What is a good Apache virtualhost entry to accomplish the typical PHP approach but for Python? How do I tell Apache "My application is in /var/www/myapplication/, execute all python files in there"? Are there any arguments to not do this in production?
- franga2000 4y agoIt's not perfect yet, but Reloadium [0] enables hot reloading of Django views. As for running python scripts like PHP, something like this should work: Options +ExecCGI AddHandler cgi-script .py Just add a Python shebang at the top of the file and it should execute. If I'm not mistaken, you'll have to print headers and then content, so you'll probably want a lib to make that easier (I don't know any, but surely they exist). [0] https://reloadium.io/features/django https://reloadium.io/features/django
- BiteCode_dev 4y agoIndeed, but: - when declaring routing in code, it's harder to shoot yourself in the foot. So many php sites expose what they should not, and .httaccess is rarely crafted correctly - renaming files don't change your website - coding locally doesn't require apache if your tooling don't need it for routing. No need for stuff like EasyPhp - python dev servers automatically reload for you on changes anyway - declaring routes and parsing them at one place to get url id and slug is less duplication - declaring url yourself mean you can use the language typing system for their checking too (see fastapi) - I rarely need an entire file for one route endpoint, making 10 files for 10 enpoints that could fit in one is overkill - wsgi servers like gunicorn will hapilly reload the workers when it receives SIGHUP in prod. No need to restart the master process manually. - restarting a process every time mean you can't benefit much from nice python features like lru_cache, process/thread pools, connection pools, etc - python is slow to start, cgi takes a toll - it's easier to control the number of max workers that run an any given time Honestly, even when coding in PHP I will use phpfpm (which is one long running process like python) and frameworks like laravel (in which you declare your routing). I understand the desire for simplicity, and the one-file/one-route declaration is easy to get into. But if I want simple, I do a static website with a bit of client side JS, not need for a backend. When I do need a backend, I much prefer long running workers and explicit route declaration.
- TekMol 4y agoNone of the points you mention are an argument against CGI for me. But it is mostly a matter of taste. There is one point I would like to address though: "python is slow to start" Python is slow. Dead slow. But not to start: echo 'print(1)' > test.py; time for i in {1..100}; do python3 test.py > /dev/null; done Gives me 1.6s echo '<?php echo(1);' > test.php; time for i in {1..100}; do php test.php > /dev/null; done Gives me 1.9s
- tyingq 4y agoI'd say they are both slow. Try Perl, Tcl, Lua or some other interpreted language that starts fast, and you'll likely see something like 200-300ms for the equivalent commands to above.
- TekMol 4y agoecho 'print 1' > test.perl; time for i in {1..100}; do perl test.perl > /dev/null; done Gives me 0.25s Clearly the winner!
- cb321 4y agoAs in so many measurement/benchmarking situations, "compared to what?" is indeed The Big Question. For example, you can also compare to a C program not doing much, overhead-wise: /usr/bin/time bash -c 'for i in {1..100}; do /bin/true; done' which gives me like 70 ms for all 100 or 0.7ms per each startup, with also some adjustment to start-up the bash driver shell itself. Even that 700 microseconds is a high number, from glibc & dynamic linking mostly. If you echo 'int main(int ac,char**av){return 0;}' > /tmp/true.c musl-gcc -static -O2 /tmp/true.c -o /tmp/true and repeat, you see 380 microseconds per each. In benchmarking scenarios requiring more elaboration than makes sense in an HN comment, I see times as low as 140 microsec per run on that same machine/OS. In fact, as you push things to low overhead extremes, you can easily see the impact of how much environment variable data is in play (`env -i` vs. not). It is true that Python start-up time is not that bad compared to a "mean diameter of the Internet in milliseconds" which is probably the relevant time scale for CGIs, but it's probably not so small as to be truly negligible, esp. once imports are happening. Also, Python3 remains quite a bit slower (1.7X slower on that same machine) to start-up than Python2 even after more than a decade of promises to claw back start-up performance. Meanwhile, on the other side of the comparison, starting up a Julia REPL seems to take quite a bit longer than the Python 16 ms..Like 340ms or 20X longer. So, the overarching point of this overlong post is just a follow-up/supporting of @tyingq's "compared to what?" with a little more detail.
- viraptor 4y ago> "one url, one file" by letting Apache handle the routing Source of many issues when someone forgets the "include auth.php" equivalent in that one specific file. (not theoretical, this happened so many times) > I have to restart the application to see changes I make. https://adamj.eu/tech/2021/12/16/introducing-django-browser-reload/ https://adamj.eu/tech/2021/12/16/introducing-django-browser-...
- hakre 4y agoWell if you already execute an application server like Apache, you should handle auth&z in there. Would be stupid to let PHP deal with it. Or would you handle the TLS termination as well in the PHP script? Well just like that. Perhaps the mistake was to do it otherwise.
- giantrobot 4y agoThe HTTP server/proxy is only going to handle TLS termination. It can also handle basic resource authentication in a pinch. But for all other auth tasks need to be done by the application. Just because a user can access a URL doesn't mean they have access to a particular row in a database or write access or something. The user data may not even live locally and be provided by an external provider which is also beyond the scope of the HTTP server. I don't know why you would think it's the HTTP front end's job to do any of that. It's all clearly the domain of the back end application.
- ThePadawan 4y agoFYI: Your link about reloading is for browser-side reloading - it seems to me that parent talks about reloading the server on code changes, which as a sibling points out, should definitely already be happening using django's `runserver`. I'd be interested to hear if parent's "typical" django app does something more involved that makes hot reloading impossible (like run in 3 levels of containers or the like).
- tjpnz 4y agoPerhaps give mod_python a look. Tried and tested but I wouldn't want to write an application like that in 2022 when I could use Flask or Fast API.
- duskwuff 4y agomod_python is dead. Last release was in 2013, and according to the web site, "there is no plan for additional releases".
- irq-1 4y agoNo new development but it still runs. If you can get by with the older version of python that's embedded, it's a good start for someone who is learning.
- duskwuff 4y ago> If you can get by with the older version of python that's embedded, it's a good start for someone who is learning. I'd have to disagree with that. Teaching a new developer how to use a tool that's already on its last legs is not setting them up for success.
- petercooper 4y agoI'm only beginning to get into Python, but maybe the solution to the "red faces" reaction is for someone to build something like what you've described and package and present it as a fantastic new way to go. Remix (https://remix.run/ https://remix.run/) is doing something like that in the JavaScript space - some of its core ideas could make a 2014 JavaScript developer bristle, but it's a great approach now and developers are loving it.
- habibur 4y agoPHP is now a days ran as fcgi, just like how Python, Ruby or Go runs. The Apache mod days have been left in the past. That you can't render a python script.py like php's script.php more likely has to do with language construction difference between the two.
- tyingq 4y ago>> That you can't render a python script.py like php's script.php more likely has to do with language construction difference between the two. You can, actually, and how close it is to the way php works is all to do with the fastcgi handler, and little to do with the language. Wsgi has configuration like WSGIScriptAlias, WSGIScriptAliasMatch, and WSGIScriptReloading that would make it almost exactly the same as default php behavior. I suppose it may not run efficiently that way, but it would run. And you don't have the built-in html templating with php, where any html file is also a valid php file.
- habibur 4y ago> I suppose it may not run efficiently that way, but it would run. And you don't have the built-in html templating with php, where any html file is also a valid php file. Indeed. On an abstract level anything can be done. Efficiency is the question.
- djxfade 4y agoNot many write PHP code like this anymore, except for perhaps some small one off projects or legacy. The reason is that it gets incredible hard to maintain, and almost impossible to test.
- hakre 4y agoif impossible to test certainly incredibly done wrong, yes and therefore to maintain. but I naturally know what you mean but its not that it must be that way. and at least there is still the one file for the entry-point. but not every entrypoint needs to have equally much bootstrapping code brought up just to process a request.
- fulafel 4y agoDjango dev server has reloading enabled out of the box, no? https://docs.djangoproject.com/en/4.0/intro/tutorial01/ https://docs.djangoproject.com/en/4.0/intro/tutorial01/ "The development server automatically reloads Python code for each request as needed"
- bastawhiz 4y ago> Are there any arguments to not do this in production? When the way the code is run is also the vehicle for returning output, you necessarily end up in a situation where you expose bad output to the user. This is an insanely common problem with PHP: warnings, errors, and stack traces are regularly returned in HTTP responses by default. Consider PHP: the output of the code (echo, closing the PHP tag, etc) gets dumped to the HTTP response, unless you configure it otherwise. Error? To the HTTP response. This exposes internal state and may be a security issue (it often is) or reveals your source code. By contrast, the only way to return data to a HTTP response in Python is to construct a response object and return it. All the built in methods for printing or generating output write to stdout/stderr or the built in python logging framework. You can get PHP-style errors, but only deliberately by having your framework catch exceptions and convert them to responses. As much as this seems like a non-issue, it's actually really dangerous when files map to URLs, because you don't want all your files being URLs. Some files are supposed to be shared, or only loaded in certain circumstances. If you can access arbitrary chunks of code directly, and then read any error output from them (or even regular-but-unintended output), you could be leaking data. Without lots of explicit manual boilerplate to block this direct access, you're running a huge risk. And this isn't just speculation. I've worked at a large PHP shop, and this was a frequent source of frustration and pain. Nobody is immune from this.
- 9dev 4y agoI would argue this is mostly a thing of the past. Properly configuring your production environment is a thing for all languages, and stuff like that simply doesn’t happen with a modern framework, ie. Anything written after 2010.
- withinboredom 4y agoPhp’s default production configuration doesn’t output any errors. Perhaps you were running the default dev configuration in production?
- bastawhiz 4y agoI publish a WordPress plugin and have worked with PHP for twenty years, and given the number of sites I've investigated that output notices and errors, what you've said seems false. Even if the stock version that is officially distributed doesn't output this by default, a wild number of hosts do.