* Unit test updates
* test_client_storage: simulate backend state expiry
* [HOS-333] Send a "reload" message to the frontend after state expiry
1. a state instance expires on the backing store
2. frontend attempts to process an event against the expired token and gets a
fresh instance of the state without router_data set
3. backend sends a "reload" message on the websocket containing the event and
immediately stops processing
4. in response to the "reload" message, frontend sends
[hydrate, update client storage, on_load, <previous_event>]
This allows the frontend and backend to re-syncronize on the state of the app
before continuing to process regular events.
If the event in (2) is a special hydrate event, then it is processed normally
by the middleware and the "reload" logic is skipped since this indicates an
initial load or a browser refresh.
* unit tests working with redis
On py3.9 and py3.10, `dict[str, str]` and other typing forms are kinda
considered classes, but they still fail when doing `issubclass`, so
specifically exclude generic aliases before calling issubclass.
Fix#4424
Bonus fix: support upcasting of pydantic v1 and v2 models
* [ENG-3953] Support pydantic BaseModel (v1 and v2) as state var
Provide serializers and mutable proxy tracking for pydantic models directly.
* conditionally define v2 serializer
Co-authored-by: Khaleel Al-Adhami <khaleel.aladhami@gmail.com>
* Add `MutableProxy._is_mutable_value` to avoid duplicate logic
* Conditionally import BaseModel to handle older pydantic v1 versions
* pre-commit fu
---------
Co-authored-by: Khaleel Al-Adhami <khaleel.aladhami@gmail.com>
Because of some dodgy logic in Base.get_value and State.dict / State.get_delta
when the value of some state var X happened to be the name of another var in
the state Y, then the value for X would be returned as the value of Y.
wat.
Fixes#4369
* allow for event handlers to ignore args
* use a constant
* dang it darglint
* forgor
* keep the tests but move them to valid place
* add metainfo to keyevent
* format code
* fix pyi files
* generate all prefixes of event types
* change format rule
* fix and test bug in config env loading
* streamline env var interpretation with @adhami3310
* improve error messages, fix invalid value for TELEMETRY_ENABLED
* just a small hint
* ruffing
* fix typo from review
* refactor - ruff broke the imports..
* cleanup imports
* more
* add internal and enum env var support
* ruff cleanup
* more global imports
* revert telemetry, it lives in rx.Config
* minor fixes/cleanup
* i missed some refs
* fix darglint
* reload config is internal
* fix EnvVar name
* add test for EnvVar + minor typing improvement
* bool tests
* was this broken?
* retain old behavior
* migrate APP_HARNESS_HEADLESS to new env var system
* migrate more APP_HARNESS env vars to new config system
* migrate SCREENSHOT_DIR to new env var system
* refactor EnvVar.get to be a method
* readd deleted functions and deprecate them
* improve EnvVar api, cleanup RELOAD_CONFIG question
* move is_prod_mode back to where it was
* [ENG-1104] patch `json.dumps` to handle `__wrapped__` objects
Unwrap proxied objects if the default serializer doesn't work.
* pre-commit fixup
* Skip default fallback logic when `cls` is specified
`cls` will provide its own default serialization mechanism, passing a `cls`
Encoder class is now also a way to opt-out of our patching shenanigans and just
use your own code.
This will work, provided the library doing the JSON encoding isn't also using
their own custom class.
* Override JSONEncoder.default instead of json.dumps
Many libraries (like httpx, used by openai), will use `from json import dumps`,
and if they do that before `reflex.state` gets imported, then they will get the
original dumps function instead of our patched one.
To workaround this, monkeypatch the `JSONEncoder.default` function instead.
This is also nicer behavior for custom subclasses of JSONEncoder; if someone
wants to opt-out of our monkeypatching, they can simply not call
`super().default(o)` in their subclass, which by default only raises a
TypeError.
---------
Co-authored-by: Nikhil Rao <nikhil@reflex.dev>
* [ENG-3970] When normal pickle fails, try dill
If dill is not installed, suggest that the user `pip install` it.
Fix#4147
* re-lock depenedencies
* Include original pickle error message for better debugging
When the pickling throws a warning and dill is not installed, include the
original pickle error.
Add a test case for an object that even dill cannot pickle to ensure error path
is hit as expected.
* py3.9 compatibility
If a non-root state was serialized, but its substates were not, then these
would not be populated when reloading the pickled state, because only substates
from the root were being populated with fresh versions.
Now, capture the substates from all fresh states and apply them to the
deserialized state for each substate to ensure that the entire state tree has
all substates instantiated after deserializing, even substates that were never
serialized originally.
* move all environment variables to the same place
* reorder things around
* move more variables to environment
* remove cyclical imports
* forgot default value for field
* for some reason type hints aren't being interpreted
* put the field type *before* not after
* make it get
* move a bit more
* add more fields
* move reflex dir
* add return
* put things somewhere else
* add custom error
* Handle rx.State subclasses defined in function
* create a new container module: `reflex.istate.dynamic` to save references to
dynamically generated substates.
* for substates with `<locals>` in the name, copy these to the container module
and update the name to avoid duplication.
* add test for "poor man" ComponentState
Fix#4128
* test_state: disable local def handling for dupe-detection test
* Track the original module and name for type hint evaluation
Also use the original name when checking for the "mangled name" pattern when
doing undeclared Var assignment checking.
* Avoid fetching substates multiple times
In the presence of computed vars, substates may be cached more than once.
* Consolidate logic in StateManagerRedis.get_state
* Suppress StateSchemaMismatchError and create a new state instance.
If the serialized state's schema does not match the current corresponding state
schema, then we have to create a new instance.
* Only serialize base vars
* Never serialize router/router_data in substates
* Hash the schema to reduce serialized size
* lru_cache the schema to avoid recomputing it
* Get default for backend var defined in mixin
If the backend var is defined in a mixin class, it won't appear in
`cls.__dict__`, but the value is still retrievable via `getattr` on `cls`.
Prefer to use the actual defined default before using
`Var.get_default_value()`.
If `Var.get_default_value()` fails, set the default to `None` such that the
backend var still gets recognized as a backend var when it is used on `self`.
----
Update test_component_state to include backend vars
Extra coverage for backend vars with and without defaults, defined in a
ComponentState/mixin class.
* fix integration test
* Simplify StateManagerDisk implementation
* Act more like the memory state manager and only track the root state in self.states
* .load_state always loads a single state or returns None
* .populate_states is the new entry point in loading from disk and it only occurs
when the root state is not known
* much fast
* StateManagerDisk now acts much more like StateManagerMemory
Treat StateManagerDisk like StateManagerMemory for AppHarness
* Handle root_state deserialized from disk
In this case, we need to initialize the whole state tree, so any non-persistent
states will still get default values, whereas on-disk states will overwrite the
defaults.
* Cache root_state under client_token for StateManagerMemory compatibility
Mainly this just makes it easier for us to write tests that work against either
Disk or Memory state managers.
* Track backend-only vars that are declared without a default value
Without this provision, declared backend vars can be accidentally shared among
all states if a mutable value is assigned to the class attribute.
* add test case for no default backend var
* remove format_state and override behavior for bare
* pass the test cases
* only do one level of dicting dataclasses
* remove dict and replace list with set
* delete unnecessary serialize calls
* remove serialize for mutable proxy
* dang it darglint