-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why should bottlepy stick to a file? #1158
Comments
it's a design decision, and you can use it simply by copying bottle.py to your directory @defnull I think you can respond better to this. |
This way is not very friendly for multi-person development, isn't it? I think this is why the development progress is so slow. |
This is part of the bottle's DNA.. see the project's headline: "It is distributed as a single file module and has no dependencies other than the Python Standard Library." In our company, it is why we have decided to select bottle over flask & others, it is so simple to have a simple look on the single file and understand the code & have an overview of everything. No dependencies, no other files, everything is included into a single location. Moving to multiple files is another project IMHO. |
Yes, the "single file, no dependencies" approach is one of the core strengths of bottle compared to other frameworks. Bottle is often used to quickly REST-ify existing tools or implement small APIs for strictly internal services, even on embedded devices where a virtualenv would be too much of a hassle sometimes. But there are more reasons:
For anyone interested in a bit of (biased) history: Bottle was first. It was inspired by an even smaller micro-framework called itty, which in turn was inspired by rubys sinatra. Armin was annoyed that I implemented everything myself and did not use his library werkzeug (or webob), so he published a clone of bottle with werkzeug bundled within a single file as an "april fools joke". He basically mocked the single-file-no-dependency approach I took for bottle. The "joke" took off, and he realized that there is actually a real demand for a web-framework just like bottle, so he started flask. You see it? Even the name is a mock. The tagline was "Like bottle, but classy" or something like that for a short time. Same API, even the same design errors (global request/response objects), but with werkzeug as a dependency. He then used his reach (he was pretty famous back then already) and pushed flask in the community, gained critical mass, and won. No need to sugarcoat it, bottle lost the popularity-battle pretty fast. But strangely enough, bottles userbase is still growing, slow and steady, even after more than 10 years in flasks shadow and with a really bad release circle. Bottle is simple, stable, fast and has enough features to be useful. Some people like it the way it is, and I'll keep it that way. |
@defnull, I am one of those bottle fans who prefers it over flask exactly for the reasons you mentioned. The only things I would like to improve are:
I realize that the first could only be done with more releases. |
I use bottle for several reasons: 1 - be one of the fastest microframeworks Things that I do not like: 2 - The error responses are in html, I created a plugin to change this and that the response was a json, maybe it could be added in the core in some way. @defnull? Things I wish I had: That point is complex since I have tried many alternatives and no "framework" offers something simple for websockets. |
@agalera it's not easy combining wsgi with websockets. See asgi ... Django has the problem |
@oz123 I know, and it is a great pain, for now I am using tornado for websockets and api en bottle. I would like to have a "websocket for humans" as requests is "HTTP for humans" and for my bottle it is "wsgi for humans" |
@agalera have you tried this? https://trio-websocket.readthedocs.io/en/stable/ |
@52lemon nothing says you must use a single file. You an split it in sub-applications # app.py
from bottle import Bottle, run
from profile import profile
app = Bottle()
@app.route('/')
def index():
return 'Hello'
app.mount('/profile', profile)
app.run() # profile.py
from bottle import Bottle
profile = Bottle()
@profile.route('/')
def profile_index():
return 'Profile'
EDIT: IT just dawned on me that this discussion is about the bottle source code itself, not bottle application code. Whoops! |
@oz123 What's exactly the issue when it comes to global request / response? Is it about performance that stumbles in framework implementation? As mentioned earlier bottle still scores well in 2019 when it comes to performance. For example you can rewrite code in no time from this:
to
In fact you can implement a fully Django-like API from scratch with bottle and other libraries. I am working with bottlepy for 3 years now and it still rocks. P.S. @defnull I think bottle is for much more than adhoc API's. |
@PyB1l Exactly, you can make your "framework" on top of the bottle and adapt it to your needs and not have to adapt to a framework designed for general purpose |
@oz123 It seems simple to use, I usually use it to send identical information to all customers (broadcast) so it's pretty simple. |
@PyB1l there is not performance issue. |
We are getting a bit off-topic here, but that's fine. @PyB1l The global request/response objects are thread-local, so normal multi-threaded WSGI servers work fine, but some asyncio or coroutine based servers implementations (e.g. gevent) break the WSGI threading model and handle more than one requests in the same thread at the same time. This caused some not-so-obvious bugs in applications in the past and is hard to protect against. It's not a bug in bottle, it is just something you need to know when choosing a server back-end. The solution is to either use a asyncio server that does not break WSGI semantics, or to monkeypatch threading.local so these objects are now task-local and no longer thread-local. Or to get a |
@defnull First thing first Congrats for bottle! I am familiar with thread-local request/response of bottle, as well as with WSGI limitations. I was not referring to async support at all. Thread local are implemented in other frameworks too, even though it's not obvious due to DI pattern that are enforced. For example a simple plugin with the following apply method (@oz123 ) method would solve this problem (it's something that bottle-inject provide by default i think). My point is this: Thread Local Response should not mess with your taste or style. Sorry if i ran off-topic
|
BTW @oz123 I too prefer explicit coding! Makes py.test way more easy |
that would work to have the data in your request, but I think the problem with asynchronous servers would not be solved since the process could change context before you assign the values |
You should put that history on the website. I knew that bottle came before flask, but not that itty.py inspired bottle. |
This is the way |
1 similar comment
This is the way |
Very inspiring discussion, bottle's code and docs are great for understanding (Python) web development. About global context, ContextVar is suitable to implement upon as a universal solution of local objects regarding threads, greenlets and coroutines(I see werkzeug has switched to it). Although this is only applicable for Python 3.7 and later versions. |
Why should bottlepy stick to a file?
The text was updated successfully, but these errors were encountered: