Compare commits

..

No commits in common. "main" and "v0.2.5" have entirely different histories.
main ... v0.2.5

733 changed files with 25133 additions and 171219 deletions

View File

@ -1,17 +1,11 @@
[run] [run]
source = reflex source = reflex
branch = true branch = true
omit =
*/pyi_generator.py
reflex/__main__.py
reflex/app_module_for_backend.py
reflex/components/chakra/*
reflex/experimental/*
[report] [report]
show_missing = true show_missing = true
# TODO bump back to 79 # TODO bump back to 79
fail_under = 70 fail_under = 75
precision = 2 precision = 2
# Regexes for lines to exclude from consideration # Regexes for lines to exclude from consideration
@ -30,11 +24,8 @@ exclude_also =
# Don't complain about abstract methods, they aren't run: # Don't complain about abstract methods, they aren't run:
@(abc\.)?abstractmethod @(abc\.)?abstractmethod
# Don't complain about overloaded methods:
@overload
ignore_errors = True ignore_errors = True
[html] [html]
directory = coverage_html_report directory = coverage_html_report

View File

@ -1,14 +0,0 @@
{
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bookworm",
"postCreateCommand": "/bin/bash -c 'python -m pip install poetry && python -m poetry install & git clone https://github.com/reflex-dev/reflex-examples; wait'",
"forwardPorts": [3000, 8000],
"portsAttributes": {
"3000": {
"label": "Frontend",
"onAutoForward": "notify"
},
"8000": {
"label": "Backend"
}
}
}

1
.github/CODEOWNERS vendored
View File

@ -1 +0,0 @@
@reflex-dev/reflex-team

View File

@ -2,6 +2,7 @@
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: '' title: ''
labels: ''
assignees: '' assignees: ''
--- ---

View File

@ -1,23 +0,0 @@
---
name: Custom Component Request
about: Suggest a new custom component for Reflex
title: ''
labels: 'custom component request'
assignees: ''
---
**Describe the Custom Component**
A clear and concise description of what the custom component does.
- What is the purpose of the custom component?
- What is the expected behavior of the custom component?
- What are the use cases for the custom component?
**Specifics (please complete the following information):**
- Do you have a specific react package in mind? (Optional):
**Additional context**
Add any other context about the custom component here.

View File

@ -1,19 +0,0 @@
---
name: Enhancement Request
about: Suggest an enhancement for an existing Reflex feature.
title: ''
labels: 'enhancement'
assignees: ''
---
**Describe the Enhancement you want**
A clear and concise description of what the improvement does.
- Which feature do you want to improve? (and what problem does it have)
- What is the benefit of the enhancement?
- Show an example/usecase were the improvement are needed.
**Additional context**
Add any other context here.

View File

@ -1,18 +0,0 @@
---
name: Feature Request
about: Suggest a new feature for Reflex
title: ''
labels: 'feature request'
assignees: ''
---
**Describe the Features**
A clear and concise description of what the features does.
- What is the purpose of the feature?
- Show an example / use cases for the new feature.
**Additional context**
Add any other context here.

View File

@ -6,7 +6,7 @@
# #
# Exit conditions: # Exit conditions:
# - Python of version `python-version` is ready to be invoked as `python`. # - Python of version `python-version` is ready to be invoked as `python`.
# - Poetry of version `poetry-version` is ready to be invoked as `poetry`. # - Poetry of version `poetry-version` is ready ot be invoked as `poetry`.
# - If `run-poetry-install` is true, deps as defined in `pyproject.toml` will have been installed into the venv at `create-venv-at-path`. # - If `run-poetry-install` is true, deps as defined in `pyproject.toml` will have been installed into the venv at `create-venv-at-path`.
name: 'Setup Reflex build environment' name: 'Setup Reflex build environment'
@ -18,7 +18,7 @@ inputs:
poetry-version: poetry-version:
description: 'Poetry version to install' description: 'Poetry version to install'
required: false required: false
default: '1.8.3' default: '1.3.1'
run-poetry-install: run-poetry-install:
description: 'Whether to run poetry install on current dir' description: 'Whether to run poetry install on current dir'
required: false required: false
@ -29,10 +29,10 @@ inputs:
default: '.venv' default: '.venv'
runs: runs:
using: 'composite' using: "composite"
steps: steps:
- name: Set up Python ${{ inputs.python-version }} - name: Set up Python ${{ inputs.python-version }}
uses: actions/setup-python@v5 uses: actions/setup-python@v4
with: with:
python-version: ${{ inputs.python-version }} python-version: ${{ inputs.python-version }}
@ -51,7 +51,7 @@ runs:
- name: Restore cached poetry install - name: Restore cached poetry install
id: restore-poetry-cache id: restore-poetry-cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v3
with: with:
path: ~/.local path: ~/.local
key: ${{ runner.os }}-python-${{ inputs.python-version }}-poetry-${{ inputs.poetry-version }} key: ${{ runner.os }}-python-${{ inputs.python-version }}-poetry-${{ inputs.poetry-version }}
@ -67,14 +67,14 @@ runs:
- if: steps.restore-poetry-cache.outputs.cache-hit != 'true' - if: steps.restore-poetry-cache.outputs.cache-hit != 'true'
name: Save poetry install to cache name: Save poetry install to cache
uses: actions/cache/save@v4 uses: actions/cache/save@v3
with: with:
path: ~/.local path: ~/.local
key: ${{ steps.restore-poetry-cache.outputs.cache-primary-key }} key: ${{ steps.restore-poetry-cache.outputs.cache-primary-key }}
- name: Restore cached project python deps - name: Restore cached project python deps
id: restore-pydeps-cache id: restore-pydeps-cache
uses: actions/cache/restore@v4 uses: actions/cache/restore@v3
with: with:
path: ${{ inputs.create-venv-at-path }} path: ${{ inputs.create-venv-at-path }}
key: ${{ runner.os }}-python-${{ inputs.python-version }}-pydeps-${{ hashFiles('**/poetry.lock') }} key: ${{ runner.os }}-python-${{ inputs.python-version }}-pydeps-${{ hashFiles('**/poetry.lock') }}
@ -93,7 +93,7 @@ runs:
- if: steps.restore-pydeps-cache.outputs.cache-hit != 'true' - if: steps.restore-pydeps-cache.outputs.cache-hit != 'true'
name: Save Python deps to cache name: Save Python deps to cache
uses: actions/cache/save@v4 uses: actions/cache/save@v3
with: with:
path: ${{ inputs.create-venv-at-path }} path: ${{ inputs.create-venv-at-path }}
key: ${{ steps.restore-pydeps-cache.outputs.cache-primary-key }} key: ${{ steps.restore-pydeps-cache.outputs.cache-primary-key }}
@ -105,9 +105,4 @@ runs:
shell: bash shell: bash
run: | run: |
source ${{ inputs.create-venv-at-path }}/*/activate source ${{ inputs.create-venv-at-path }}/*/activate
poetry install --only-root --no-interaction poetry install --only-root --no-interaction
- name: Install uv
shell: bash
run: |
poetry run pip install uv

View File

@ -1,2 +0,0 @@
paths-ignore:
- "**/tests/**"

View File

@ -1,7 +1,7 @@
### All Submissions: ### All Submissions:
- [ ] Have you followed the guidelines stated in [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) file? - [ ] Have you followed the guidelines stated in [CONTRIBUTING.md](https://github.com/pynecone-io/pynecone/blob/main/CONTRIBUTING.md) file?
- [ ] Have you checked to ensure there aren't any other open [Pull Requests](https://github.com/reflex-dev/reflex/pulls ) for the desired changed? - [ ] Have you checked to ensure there aren't any other open [Pull Requests](https://github.com/pynecone-io/pynecone/pulls ) for the desired changed?
<!-- You can erase any parts of this template not applicable to your Pull Request. --> <!-- You can erase any parts of this template not applicable to your Pull Request. -->

View File

@ -1,143 +0,0 @@
name: benchmarking
on:
pull_request:
types:
- closed
paths-ignore:
- "**/*.md"
permissions:
contents: read
defaults:
run:
shell: bash
env:
PYTHONIOENCODING: "utf8"
TELEMETRY_ENABLED: false
NODE_OPTIONS: "--max_old_space_size=8192"
PR_TITLE: ${{ github.event.pull_request.title }}
jobs:
reflex-web:
# if: github.event.pull_request.merged == true
strategy:
fail-fast: false
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest]
python-version: ["3.12.8"]
node-version: ["18.x"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Install LightHouse Pre-reqs / Run LightHouse
run: |
# Check that npm is home
npm -v
poetry run bash benchmarks/lighthouse.sh ./reflex-web prod
env:
LHCI_GITHUB_APP_TOKEN: $
- name: Run Benchmarks
# Only run if the database creds are available in this context.
run: poetry run python benchmarks/benchmark_lighthouse.py "$GITHUB_SHA" ./integration/benchmarks/.lighthouseci
env:
GITHUB_SHA: ${{ github.sha }}
reflex-dist-size: # This job is used to calculate the size of the Reflex distribution (wheel file)
if: github.event.pull_request.merged == true
timeout-minutes: 30
strategy:
# Prioritize getting more information out of the workflow (even if something fails)
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: 3.12.8
run-poetry-install: true
create-venv-at-path: .venv
- name: Build reflex
run: |
poetry build
- name: Upload benchmark results
# Only run if the database creds are available in this context.
run:
poetry run python benchmarks/benchmark_package_size.py --os ubuntu-latest
--python-version 3.12.8 --commit-sha "${{ github.sha }}" --pr-id "${{ github.event.pull_request.id }}"
--branch-name "${{ github.head_ref || github.ref_name }}"
--path ./dist
reflex-venv-size: # This job calculates the total size of Reflex and its dependencies
if: github.event.pull_request.merged == true
timeout-minutes: 30
strategy:
# Prioritize getting more information out of the workflow (even if something fails)
fail-fast: false
matrix:
# Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.12.8"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up python
id: setup-python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.3.1
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: .venv
- name: Run poetry install
shell: bash
run: |
python -m venv .venv
source .venv/*/activate
poetry install --without dev --no-interaction --no-root
- name: Install uv
shell: bash
run: |
poetry run pip install uv
- name: calculate and upload size
run:
poetry run python benchmarks/benchmark_package_size.py --os "${{ matrix.os }}"
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
--pr-id "${{ github.event.pull_request.id }}"
--branch-name "${{ github.head_ref || github.ref_name }}"
--path ./.venv

View File

@ -1,40 +0,0 @@
name: check-generated-pyi
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
on:
push:
branches: ["main"]
# We don't just trigger on make_pyi.py and the components dir, because
# there are other things that can change the generator output
# e.g. black version, reflex.Component, reflex.Var.
paths-ignore:
- "**/*.md"
pull_request:
branches: ["main"]
paths-ignore:
- "**/*.md"
jobs:
check-generated-pyi-components:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: "3.12.8"
run-poetry-install: true
create-venv-at-path: .venv
- run: |
poetry run python scripts/make_pyi.py
if [[ $(git status --porcelain) ]]; then
git status
git diff
echo "ERROR: make_pyi.py output is out of date. Please run scripts/make_pyi.py and commit the changes."
exit 1
else
echo "No diffs - AOK!"
fi

View File

@ -1,40 +0,0 @@
name: integration-node-latest
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
TELEMETRY_ENABLED: false
REFLEX_USE_SYSTEM_NODE: true
jobs:
check_latest_node:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.12.8"]
split_index: [1, 2]
node-version: ["node"]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: |
poetry run uv pip install pyvirtualdisplay pillow pytest-split
poetry run playwright install --with-deps
- run: |
poetry run pytest tests/test_node_version.py
poetry run pytest tests/integration --splits 2 --group ${{matrix.split_index}}

View File

@ -1,86 +0,0 @@
name: check-outdated-dependencies
on:
push: # This will trigger the action when a pull request is opened or updated.
branches:
- "release/**" # This will trigger the action when any branch starting with "release/" is created.
workflow_dispatch: # Allow manual triggering if needed.
jobs:
backend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- uses: ./.github/actions/setup_build_env
with:
python-version: '3.10'
run-poetry-install: true
create-venv-at-path: .venv
- name: Check outdated backend dependencies
run: |
outdated=$(poetry show -oT)
echo "Outdated:"
echo "$outdated"
filtered_outdated=$(echo "$outdated" | grep -vE 'pyright|ruff' || true)
if [ ! -z "$filtered_outdated" ]; then
echo "Outdated dependencies found:"
echo "$filtered_outdated"
exit 1
else
echo "All dependencies are up to date. (pyright and ruff are ignored)"
fi
frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: "3.10.16"
run-poetry-install: true
create-venv-at-path: .venv
- name: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install $(grep -ivE "reflex " requirements.txt)
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Run Website and Check for errors
run: |
poetry run bash scripts/integration.sh ./reflex-web dev
- name: Check outdated frontend dependencies
working-directory: ./reflex-web/.web
run: |
raw_outdated=$(/home/runner/.local/share/reflex/bun/bin/bun outdated)
outdated=$(echo "$raw_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\|' || true)
echo "Outdated:"
echo "$outdated"
# Ignore 3rd party dependencies that are not updated.
filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images|ag-grid' || true)
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
if [ ! -z "$no_extra" ]; then
echo "Outdated dependencies found:"
echo "$filtered_outdated"
exit 1
else
echo "All dependencies are up to date. (3rd party packages are ignored)"
fi

View File

@ -1,103 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
schedule:
- cron: "36 7 * * 4"
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
- language: python
build-mode: none
- language: actions
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config-file: .github/codeql-config.yml
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@ -1,17 +0,0 @@
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
with:
allow-licenses: Apache-2.0, BSD-2-Clause, BSD-3-Clause, HPND, ISC, MIT, MPL-2.0, Unlicense, Python-2.0, Python-2.0.1, Apache-2.0 AND MIT, BSD-2-Clause AND BSD-3-Clause, Apache-2.0 AND BSD-3-Clause
allow-dependencies-licenses: 'pkg:pypi/lazy-loader'

View File

@ -1,56 +1,37 @@
name: integration-app-harness name: integration-app-harness
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
on: on:
push: push:
branches: ["main"] branches: [ "main" ]
paths-ignore: paths-ignore:
- "**/*.md" - '**/*.md'
pull_request: pull_request:
branches: ["main"] branches: [ "main" ]
paths-ignore: paths-ignore:
- "**/*.md" - '**/*.md'
permissions: permissions:
contents: read contents: read
jobs: jobs:
integration-app-harness: integration-app-harness:
timeout-minutes: 30 runs-on: ubuntu-latest
strategy:
matrix:
state_manager: ["redis", "memory"]
python-version: ["3.11.11", "3.12.8", "3.13.1"]
split_index: [1, 2]
fail-fast: false
runs-on: ubuntu-22.04
services:
# Label used to access the service container
redis:
image: ${{ matrix.state_manager == 'redis' && 'redis' || '' }}
# Set health checks to wait until redis has started
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps port 6379 on service container to the host
- 6379:6379
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
python-version: ${{ matrix.python-version }} python-version: "3.11"
run-poetry-install: true run-poetry-install: true
create-venv-at-path: .venv create-venv-at-path: .venv
- run: poetry run uv pip install pyvirtualdisplay pillow pytest-split pytest-retry - run: poetry run pip install pyvirtualdisplay pillow
- name: Run app harness tests - name: Run app harness tests
env: env:
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }} SCREENSHOT_DIR: /tmp/screenshots
run: | run: |
poetry run playwright install chromium poetry run pytest integration
poetry run pytest tests/integration --retries 3 --maxfail=5 --splits 2 --group ${{matrix.split_index}} - uses: actions/upload-artifact@v3
name: Upload failed test screenshots
if: always()
with:
name: failed_test_screenshots
path: /tmp/screenshots

View File

@ -2,17 +2,13 @@ name: integration-tests
on: on:
push: push:
branches: ["main"] branches: [ main ]
paths-ignore: paths-ignore:
- "**/*.md" - '**/*.md'
pull_request: pull_request:
branches: ["main"] branches: [ main ]
paths-ignore: paths-ignore:
- "**/*.md" - '**/*.md'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
permissions: permissions:
contents: read contents: read
@ -28,52 +24,41 @@ env:
# - Catch encoding errors when printing logs # - Catch encoding errors when printing logs
# - Best effort print lines that contain illegal chars (map to some default char, etc.) # - Best effort print lines that contain illegal chars (map to some default char, etc.)
PYTHONIOENCODING: "utf8" PYTHONIOENCODING: "utf8"
TELEMETRY_ENABLED: false
NODE_OPTIONS: "--max_old_space_size=8192"
PR_TITLE: ${{ github.event.pull_request.title }}
jobs: jobs:
example-counter-and-nba-proxy: example-counter:
env:
OUTPUT_FILE: import_benchmark.json
timeout-minutes: 30
strategy: strategy:
# Prioritize getting more information out of the workflow (even if something fails) # Prioritize getting more information out of the workflow (even if something fails)
fail-fast: false fail-fast: false
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest] os: [ ubuntu-latest, windows-latest, macos-latest ]
python-version: ['3.10.16', '3.11.11', '3.12.8', '3.13.1'] python-version: [ "3.8", "3.9", "3.10", "3.11" ]
exclude: node-version: [ "16.x" ]
- os: windows-latest
python-version: "3.11.11"
- os: windows-latest
python-version: '3.10.16'
include:
- os: windows-latest
python-version: "3.11.9"
- os: windows-latest
python-version: '3.10.11'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
run-poetry-install: true run-poetry-install: true
create-venv-at-path: .venv create-venv-at-path: .venv
- name: Clone Reflex Examples Repo - name: Clone Reflex Examples Repo
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
repository: reflex-dev/reflex-examples repository: reflex-dev/reflex-examples
path: reflex-examples path: reflex-examples
- name: Install requirements for counter example - name: Install requirements for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
run: | run: |
poetry run uv pip install -r requirements.txt poetry run pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Check export --backend-only before init for counter example - name: Check export --backend-only before init for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
run: | run: |
@ -94,40 +79,23 @@ jobs:
# Check that npm is home # Check that npm is home
npm -v npm -v
poetry run bash scripts/integration.sh ./reflex-examples/counter dev poetry run bash scripts/integration.sh ./reflex-examples/counter dev
- name: Install requirements for nba proxy example
working-directory: ./reflex-examples/nba-proxy
run: |
poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Check export --backend-only before init for nba-proxy example
working-directory: ./reflex-examples/nba-proxy
run: |
poetry run reflex export --backend-only
- name: Init Website for nba-proxy example
working-directory: ./reflex-examples/nba-proxy
run: |
poetry run reflex init --loglevel debug
- name: Run Website and Check for errors
run: |
# Check that npm is home
npm -v
poetry run bash scripts/integration.sh ./reflex-examples/nba-proxy dev
reflex-web: reflex-web:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest] os: [ ubuntu-latest, windows-latest, macos-latest ]
python-version: ["3.11.11", "3.12.8"] python-version: [ "3.10", "3.11" ]
node-version: [ "16.x" ]
env:
REFLEX_WEB_WINDOWS_OVERRIDE: "1"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
@ -135,80 +103,15 @@ jobs:
create-venv-at-path: .venv create-venv-at-path: .venv
- name: Clone Reflex Website Repo - name: Clone Reflex Website Repo
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
repository: reflex-dev/reflex-web repository: reflex-dev/reflex-web
ref: main ref: reflex-ci
path: reflex-web path: reflex-web
- name: Install Requirements for reflex-web - name: Install Requirements for reflex-web
working-directory: ./reflex-web working-directory: ./reflex-web
run: poetry run uv pip install $(grep -ivE "reflex " requirements.txt) run: poetry run pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Init Website for reflex-web
working-directory: ./reflex-web
run: poetry run reflex init
- name: Run Website and Check for errors
run: |
# Check that npm is home
npm -v
poetry run bash scripts/integration.sh ./reflex-web prod
rx-shout-from-template:
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: "3.11.11"
run-poetry-install: true
create-venv-at-path: .venv
- name: Create app directory
run: mkdir rx-shout-from-template
- name: Init reflex-web from template
run: poetry run reflex init --template https://github.com/masenf/rx_shout
working-directory: ./rx-shout-from-template
- name: ignore reflex pin in requirements
run: sed -i -e '/reflex==/d' requirements.txt
working-directory: ./rx-shout-from-template
- name: Install additional dependencies
run: poetry run uv pip install -r requirements.txt
working-directory: ./rx-shout-from-template
- name: Run Website and Check for errors
run: |
# Check that npm is home
npm -v
poetry run bash scripts/integration.sh ./rx-shout-from-template prod
reflex-web-macos:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
# Note: py311 version chosen due to available arm64 darwin builds.
python-version: ["3.11.9", "3.12.8"]
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Clone Reflex Website Repo
uses: actions/checkout@v4
with:
repository: reflex-dev/reflex-web
ref: main
path: reflex-web
- name: Install Requirements for reflex-web
working-directory: ./reflex-web
run: poetry run uv pip install -r requirements.txt
- name: Install additional dependencies for DB access
run: poetry run uv pip install psycopg
- name: Init Website for reflex-web - name: Init Website for reflex-web
working-directory: ./reflex-web working-directory: ./reflex-web
run: poetry run reflex init run: poetry run reflex init

View File

@ -1,44 +1,33 @@
name: integration-tests-wsl name: integration-tests-wsl
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
on: on:
push: push:
branches: ['main'] branches: [ "main" ]
paths-ignore: paths-ignore:
- '**/*.md' - '**/*.md'
pull_request: pull_request:
branches: ['main'] branches: [ main ]
paths-ignore: paths-ignore:
- '**/*.md' - '**/*.md'
permissions: permissions:
contents: read contents: read
env:
TELEMETRY_ENABLED: false
NODE_OPTIONS: '--max_old_space_size=4096'
jobs: jobs:
example-counter-wsl: example-counter-wsl:
timeout-minutes: 30
# 2019 is more stable with WSL in GH actions # 2019 is more stable with WSL in GH actions
# https://github.com/actions/runner-images/issues/5151 # https://github.com/actions/runner-images/issues/5151
# Confirmed through trial and error. 2022 has >80% failure rate (probably BSOD) # Confirmed through trial and error. 2022 has >80% failure rate (probably BSOD)
runs-on: windows-2019 runs-on: windows-2019
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Clone Reflex Examples Repo - name: Clone Reflex Examples Repo
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
repository: reflex-dev/reflex-examples repository: reflex-dev/reflex-examples
path: reflex-examples path: reflex-examples
- uses: Vampire/setup-wsl@v3 - uses: Vampire/setup-wsl@v2
with:
distribution: Ubuntu-24.04
- name: Install Python - name: Install Python
shell: wsl-bash {0} shell: wsl-bash {0}
@ -58,42 +47,32 @@ jobs:
run: | run: |
poetry install poetry install
- name: Install uv
shell: wsl-bash {0}
run: |
poetry run pip install uv
- name: Install requirements for counter example - name: Install requirements for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
poetry run uv pip install -r requirements.txt poetry run pip install -r requirements.txt
- name: Check export --backend-only before init for counter example - name: Check export --backend-only before init for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
export TELEMETRY_ENABLED=false
poetry run reflex export --backend-only poetry run reflex export --backend-only
- name: Check run --backend-only before init for counter example - name: Check run --backend-only before init for counter example
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
export TELEMETRY_ENABLED=false
dos2unix scripts/integration.sh dos2unix scripts/integration.sh
poetry run bash scripts/integration.sh ./reflex-examples/counter dev 8001 --backend-only --backend-port 8001 poetry run bash scripts/integration.sh ./reflex-examples/counter dev 8001 --backend-only --backend-port 8001
- name: Init Website for counter example - name: Init Website for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
export TELEMETRY_ENABLED=false
poetry run reflex init --loglevel debug poetry run reflex init --loglevel debug
- name: Check export for counter example - name: Check export for counter example
working-directory: ./reflex-examples/counter working-directory: ./reflex-examples/counter
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
export TELEMETRY_ENABLED=false
poetry run reflex export --frontend-only --loglevel debug poetry run reflex export --frontend-only --loglevel debug
- name: Run Website and Check for errors - name: Run Website and Check for errors
shell: wsl-bash {0} shell: wsl-bash {0}
run: | run: |
export TELEMETRY_ENABLED=false
poetry run bash scripts/integration.sh ./reflex-examples/counter dev poetry run bash scripts/integration.sh ./reflex-examples/counter dev

View File

@ -1,34 +0,0 @@
name: performance-tests
on:
push:
branches:
- "main" # or "master"
paths-ignore:
- "**/*.md"
pull_request:
workflow_dispatch:
env:
TELEMETRY_ENABLED: false
NODE_OPTIONS: "--max_old_space_size=8192"
PR_TITLE: ${{ github.event.pull_request.title }}
APP_HARNESS_HEADLESS: 1
PYTHONUNBUFFERED: 1
jobs:
benchmarks:
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: 3.12.8
run-poetry-install: true
create-venv-at-path: .venv
- name: Run benchmarks
uses: CodSpeedHQ/action@v3
with:
token: ${{ secrets.CODSPEED_TOKEN }}
run: poetry run pytest tests/benchmarks --codspeed

View File

@ -1,34 +1,28 @@
name: pre-commit name: pre-commit
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
on: on:
pull_request: pull_request:
branches: ["main"] branches: [main]
push: push:
# Note even though this job is called "pre-commit" and runs "pre-commit", this job will run # Note even though this job is called "pre-commit" and runs "pre-commit", this job will run
# also POST-commit on main also! In case there are mishandled merge conflicts / bad auto-resolves # also POST-commit on main also! In case there are mishandled merge conflicts / bad auto-resolves
# when merging into main branch. # when merging into main branch.
branches: ["main"] branches: [main]
jobs: jobs:
pre-commit: pre-commit:
timeout-minutes: 30
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
# running vs. one version of Python is OK # running vs. one version of Python is OK
# i.e. ruff, black, etc. # i.e. ruff, black, etc.
python-version: 3.12.8 python-version: 3.11
run-poetry-install: true run-poetry-install: true
shell: bash
create-venv-at-path: .venv create-venv-at-path: .venv
# TODO pre-commit related stuff can be cached too (not a bottleneck yet) # TODO pre-commit related stuff can be cached too (not a bottleneck yet)
- run: | - run: |
poetry run uv pip install pre-commit poetry run pip install pre-commit
poetry run pre-commit run --all-files poetry run pre-commit run --all-files
env:
SKIP: update-pyi-files

View File

@ -1,16 +1,13 @@
name: reflex-init-in-docker-test name: reflex-init-in-docker-test
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
on: on:
push: push:
branches: ['main'] branches: [ "main" ]
paths-ignore: paths-ignore:
- '**/*.md' - '**/*.md'
pull_request: pull_request:
branches: ['main'] branches:
- main
paths-ignore: paths-ignore:
- '**/*.md' - '**/*.md'
@ -18,15 +15,14 @@ jobs:
# TODO we can extend to various starting points (e.g. Ubuntu with node, without node, with unzip, without unzip, etc.) # TODO we can extend to various starting points (e.g. Ubuntu with node, without node, with unzip, without unzip, etc.)
# Currently starting point is: Ubuntu + unzip, xz-utils, Python suite. No node. # Currently starting point is: Ubuntu + unzip, xz-utils, Python suite. No node.
reflex-install-and-init: reflex-install-and-init:
timeout-minutes: 30
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- shell: bash - shell: bash
run: | run: |
# Run reflex init in a docker container # Run reflex init in a docker container
# cwd is repo root # cwd is repo root
docker build -f tests/integration/init-test/Dockerfile -t reflex-init-test tests/integration/init-test docker build -f integration/init-test/Dockerfile -t reflex-init-test integration/init-test
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/tests/integration/init-test/in_docker_test_script.sh docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/integration/init-test/in_docker_test_script.sh

View File

@ -1,109 +1,40 @@
name: unit-tests name: unit-tests
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
cancel-in-progress: true
on: on:
push: push:
branches: ["main"] branches: [ "main" ]
paths-ignore: paths-ignore:
- "**/*.md" - '**/*.md'
pull_request: pull_request:
branches: ["main"] branches: [ "main" ]
paths-ignore: paths-ignore:
- "**/*.md" - '**/*.md'
permissions: permissions:
contents: read contents: read
defaults: defaults:
run: run:
shell: bash shell: bash
jobs: jobs:
unit-tests: unit-tests:
timeout-minutes: 30
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest] os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.10.16", "3.11.11", "3.12.8", "3.13.1"] # TODO consider bringing back 3.7. Note Windows x 3.7 fails from some sqlalchemy related problem
# Windows is a bit behind on Python version availability in Github python-version: ["3.8", "3.9", "3.10", "3.11"]
exclude:
- os: windows-latest
python-version: "3.11.11"
- os: windows-latest
python-version: "3.10.16"
include:
- os: windows-latest
python-version: "3.11.9"
- os: windows-latest
python-version: "3.10.11"
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
# Service containers to run with `runner-job`
services:
# Label used to access the service container
redis:
image: ${{ matrix.os == 'ubuntu-latest' && 'redis' || '' }}
# Set health checks to wait until redis has started
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps port 6379 on service container to the host
- 6379:6379
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
run-poetry-install: true run-poetry-install: true
create-venv-at-path: .venv create-venv-at-path: .venv
- name: Run unit tests - name: Run unit tests
run: | run: |
export PYTHONUNBUFFERED=1 export PYTHONUNBUFFERED=1
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report= poetry run pytest tests --cov --no-cov-on-fail --cov-report=
- name: Run unit tests w/ redis - run: poetry run coverage html
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
export PYTHONUNBUFFERED=1
export REDIS_URL=redis://localhost:6379
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
# Change to explicitly install v1 when reflex-hosting-cli is compatible with v2
- name: Run unit tests w/ pydantic v1
run: |
export PYTHONUNBUFFERED=1
poetry run uv pip install "pydantic~=1.10"
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- name: Generate coverage report
run: poetry run coverage html
unit-tests-macos:
timeout-minutes: 30
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
# Note: py310, py311 versions chosen due to available arm64 darwin builds.
python-version: ["3.10.11", "3.11.9", "3.12.8", "3.13.1"]
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup_build_env
with:
python-version: ${{ matrix.python-version }}
run-poetry-install: true
create-venv-at-path: .venv
- name: Run unit tests
run: |
export PYTHONUNBUFFERED=1
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
- name: Run unit tests w/ pydantic v1
run: |
export PYTHONUNBUFFERED=1
poetry run uv pip install "pydantic~=1.10"
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=

9
.gitignore vendored
View File

@ -1,18 +1,9 @@
**/.DS_Store **/.DS_Store
**/*.pyc **/*.pyc
assets/external/*
dist/* dist/*
examples/ examples/
.web
.states
.idea .idea
.vscode .vscode
.coverage .coverage
.coverage.* .coverage.*
.venv
venv venv
requirements.txt
.pyi_generator_last_run
.pyi_generator_diff
reflex.db
.codspeed

View File

@ -1,43 +1,25 @@
fail_fast: true
repos: repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit - repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.9.6 rev: v0.0.244
hooks: hooks:
- id: ruff-format - id: ruff
args: [reflex, tests] args: [--fix, --exit-non-zero-on-fix]
- id: ruff
args: ["--fix", "--exit-non-zero-on-fix"]
exclude: '^integration/benchmarks/'
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
args: ["reflex"]
# Run pyi check before pyright because pyright can fail if pyi files are wrong.
- repo: local
hooks:
- id: update-pyi-files
name: update-pyi-files
always_run: true
language: system
require_serial: true
description: 'Update pyi files as needed'
entry: python3 scripts/make_pyi.py
- repo: https://github.com/RobertCraigie/pyright-python - repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.393 rev: v1.1.313
hooks: hooks:
- id: pyright - id: pyright
args: [reflex, tests] args: [integration, reflex, tests]
language: system language: system
- repo: https://github.com/terrencepreilly/darglint - repo: https://github.com/terrencepreilly/darglint
rev: v1.8.1 rev: v1.8.1
hooks: hooks:
- id: darglint - id: darglint
exclude: '^reflex/reflex.py' exclude: '^reflex/reflex.py'
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
args: [integration, reflex, tests]

View File

@ -5,7 +5,7 @@
We as members, contributors, and leaders pledge to make participation in our We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socioeconomic status, identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity nationality, personal appearance, race, religion, or sexual identity
and orientation. and orientation.

View File

@ -2,50 +2,58 @@
For an extensive guide on the different ways to contribute to Reflex see our [Contributing Guide on Notion](https://www.notion.so/reflex-dev/2107ab2bc166497db951b8d742748284?v=f0eaff78fa984b5ab15d204af58907d7). For an extensive guide on the different ways to contribute to Reflex see our [Contributing Guide on Notion](https://www.notion.so/reflex-dev/2107ab2bc166497db951b8d742748284?v=f0eaff78fa984b5ab15d204af58907d7).
## Running a Local Build of Reflex
Here is a quick guide on how to run Reflex repo locally so you can start contributing to the project.
## Running a Local Build of Reflex
Here is a quick guide to how the run Reflex repo locally so you can start contributing to the project.
**Prerequisites:** **Prerequisites:**
- Python >= 3.7
- Python >= 3.10
- Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info). - Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info).
**1. Fork this repository:**
Fork this repository by clicking on the `Fork` button on the top right.
**2. Clone Reflex and navigate into the repo:**
**1. Clone Reflex and navigate into the repo:**
``` bash ``` bash
git clone https://github.com/<YOUR-USERNAME>/reflex.git git clone https://github.com/reflex-dev/reflex.git
cd reflex cd reflex
``` ```
**3. Install your local Reflex build:** **2. Install your local Reflex build:**
``` bash ``` bash
poetry install poetry install
``` ```
**3. Now create an examples folder so you can test the local Python build in this repository.**
**4. Now create an examples folder so you can test the local Python build in this repository.** * We have the `examples` folder in the `.gitignore`, so your changes in `reflex/examples` won't be reflected in your commit.
- We have the `examples` folder in the `.gitignore`, so your changes in `reflex/examples` won't be reflected in your commit.
``` bash ``` bash
mkdir examples mkdir examples
cd examples cd examples
``` ```
**5. Init and Run** **4. Init and Run**
``` bash
poetry run reflex init
poetry run reflex run
```
All the changes you make to the repository will be reflected in your running app.
## 🧪 Testing and QA
Within the 'test' directory of Reflex you can add to a test file already there or create a new test python file if it doesn't fit into the existing layout.
#### What to unit test?
- Any feature or significant change that has been added.
- Any edge cases or potential problem areas.
- Any interactions between different parts of the code.
Now Init/Run
``` bash ``` bash
poetry run reflex init poetry run reflex init
poetry run reflex run poetry run reflex run
``` ```
All the changes you make to the repository will be reflected in your running app. All the changes you make to the repository will be reflected in your running app.
* We have the examples folder in the .gitignore, so your changes in reflex/examples won't be reflected in your commit.
- We have the examples folder in the .gitignore, so your changes in reflex/examples won't be reflected in your commit.
## 🧪 Testing and QA ## 🧪 Testing and QA
@ -53,64 +61,38 @@ Any feature or significant change added should be accompanied with unit tests.
Within the 'test' directory of Reflex you can add to a test file already there or create a new test python file if it doesn't fit into the existing layout. Within the 'test' directory of Reflex you can add to a test file already there or create a new test python file if it doesn't fit into the existing layout.
#### What to unit test? What to unit test?
- Any feature or significant change that has been added. - Any feature or significant change that has been added.
- Any edge cases or potential problem areas. - Any edge cases or potential problem areas.
- Any interactions between different parts of the code. -Any interactions between different parts of the code.
## ✅ Making a PR ## ✅ Making a PR
Once you solve a current issue or improvement to Reflex, you can make a PR, and we will review the changes. Once you solve a current issue or improvement to Reflex, you can make a pr, and we will review the changes.
Before submitting, a pull request, ensure the following steps are taken and test passing. Before submitting, a pull request, ensure the following steps are taken and test passing.
In your `reflex` directory run make sure all the unit tests are still passing using the following command. In your `reflex` directory run make sure all the unit tests are still passing using the following command.
This will fail if code coverage is below 70%. This will fail if code coverage is below 80%.
``` bash ``` bash
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report= poetry run pytest tests --cov --no-cov-on-fail --cov-report=
``` ```
Next make sure all the following tests pass. This ensures that every new change has proper documentation and type checking. Next make sure all the following tests pass. This ensures that every new change has proper documentation and type checking.
``` bash ``` bash
poetry run ruff check . poetry run ruff check .
poetry run pyright reflex tests poetry run pyright reflex tests
find reflex tests -name "*.py" -not -path reflex/reflex.py | xargs poetry run darglint find reflex tests -name "*.py" -not -path reflex/reflex.py | xargs poetry run darglint
``` ```
Finally, run `black` to format your code.
Finally, run `ruff` to format your code.
``` bash ``` bash
poetry run ruff format . poetry run black reflex tests
``` ```
Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit. Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and Black will run automatically before each commit.
Note that pre-commit will only be installed when you use a Python version >= 3.10. Note that pre-commit will only be installed when you use a Python version >= 3.8.
``` bash ``` bash
pre-commit install pre-commit install
``` ```
That's it you can now submit your PR. Thanks for contributing to Reflex! That's it you can now submit your pr. Thanks for contributing to Reflex!
## Editing Templates
To edit the templates in Reflex you can do so in two way.
Change to the basic `blank` template can be done in the `reflex/.templates/apps/blank` directory.
Others templates can be edited in their own repository. For example the `sidebar` template can be found in the [`reflex-sidebar`](https://github.com/reflex-dev/sidebar-template) repository.
## Other Notes
For some pull requests when adding new components you will have to generate a pyi file for the new component. This is done by running the following command in the `reflex` directory.
(Please check in with the team before adding a new component to Reflex we are cautious about adding new components to Reflex's core.)
``` bash
poetry run python scripts/make_pyi.py
```

107
README.md
View File

@ -10,31 +10,18 @@
### **✨ Performant, customizable web apps in pure Python. Deploy in seconds. ✨** ### **✨ Performant, customizable web apps in pure Python. Deploy in seconds. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex) [![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg) ![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction) [![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ) [![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div> </div>
--- ---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
--- ---
# Reflex
Reflex is a library to build full-stack web apps in pure Python.
Key features:
* **Pure Python** - Write your app's frontend and backend all in Python, no need to learn Javascript.
* **Full Flexibility** - Reflex is easy to get started with, but can also scale to complex apps.
* **Deploy Instantly** - After building, deploy your app with a [single command](https://reflex.dev/docs/hosting/deploy-quick-start/) or host it on your own server.
See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) to learn how Reflex works under the hood.
## ⚙️ Installation ## ⚙️ Installation
Open a terminal and run (Requires Python 3.10+): Open a terminal and run (Requires Python 3.7+):
```bash ```bash
pip install reflex pip install reflex
@ -67,7 +54,7 @@ Now you can modify the source code in `my_app_name/my_app_name.py`. Reflex has f
## 🫧 Example App ## 🫧 Example App
Let's go over an example: creating an image generation UI around [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). For simplicity, we just call the [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), but you could replace this with an ML model run locally. Let's go over an example: creating an image generation UI around DALL·E. For simplicity, we just call the OpenAI API, but you could replace this with an ML model run locally.
&nbsp; &nbsp;
@ -79,18 +66,14 @@ Let's go over an example: creating an image generation UI around [DALL·E](https
Here is the complete code to create this. This is all done in one Python file! Here is the complete code to create this. This is all done in one Python file!
```python ```python
import reflex as rx import reflex as rx
import openai import openai
openai_client = openai.OpenAI() openai.api_key = "YOUR_API_KEY"
class State(rx.State): class State(rx.State):
"""The app state.""" """The app state."""
prompt = "" prompt = ""
image_url = "" image_url = ""
processing = False processing = False
@ -103,33 +86,33 @@ class State(rx.State):
self.processing, self.complete = True, False self.processing, self.complete = True, False
yield yield
response = openai_client.images.generate( response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
prompt=self.prompt, n=1, size="1024x1024" self.image_url = response["data"][0]["url"]
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True self.processing, self.complete = False, True
def index(): def index():
return rx.center( return rx.center(
rx.vstack( rx.vstack(
rx.heading("DALL-E", font_size="1.5em"), rx.heading("DALL·E"),
rx.input( rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button( rx.button(
"Generate Image", "Generate Image",
on_click=State.get_image, on_click=State.get_image,
width="25em", is_loading=State.processing,
loading=State.processing width="100%",
), ),
rx.cond( rx.cond(
State.complete, State.complete,
rx.image(src=State.image_url, width="20em"), rx.image(
src=State.image_url,
height="25em",
width="25em",
)
), ),
align="center", padding="2em",
shadow="lg",
border_radius="lg",
), ),
width="100%", width="100%",
height="100vh", height="100vh",
@ -137,20 +120,12 @@ def index():
# Add state and page to the app. # Add state and page to the app.
app = rx.App() app = rx.App()
app.add_page(index, title="Reflex:DALL-E") app.add_page(index, title="reflex:DALL·E")
app.compile()
``` ```
## Let's break this down. ## Let's break this down.
<div align="center">
<img src="docs/images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
</div>
### **Reflex UI** ### **Reflex UI**
Let's start with the UI. Let's start with the UI.
@ -167,7 +142,7 @@ This `index` function defines the frontend of the app.
We use different components such as `center`, `vstack`, `input`, and `button` to build the frontend. Components can be nested within each other We use different components such as `center`, `vstack`, `input`, and `button` to build the frontend. Components can be nested within each other
to create complex layouts. And you can use keyword args to style them with the full power of CSS. to create complex layouts. And you can use keyword args to style them with the full power of CSS.
Reflex comes with [60+ built-in components](https://reflex.dev/docs/library) to help you get started. We are actively adding more components, and it's easy to [create your own components](https://reflex.dev/docs/wrapping-react/overview/). Reflex comes with [60+ built-in components](https://reflex.dev/docs/library) to help you get started. We are actively adding more components, and it's easy to [create your own components](https://reflex.dev/docs/advanced-guide/wrapping-react).
### **State** ### **State**
@ -180,12 +155,11 @@ class State(rx.State):
image_url = "" image_url = ""
processing = False processing = False
complete = False complete = False
``` ```
The state defines all the variables (called vars) in an app that can change and the functions that change them. The state defines all the variables (called vars) in an app that can change and the functions that change them.
Here the state is comprised of a `prompt` and `image_url`. There are also the booleans `processing` and `complete` to indicate when to disable the button (during image generation) and when to show the resulting image. Here the state is comprised of a `prompt` and `image_url`. There are also the booleans `processing` and `complete` to indicate when to show the circular progress and image.
### **Event Handlers** ### **Event Handlers**
@ -197,10 +171,8 @@ def get_image(self):
self.processing, self.complete = True, False self.processing, self.complete = True, False
yield yield
response = openai_client.images.generate( response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
prompt=self.prompt, n=1, size="1024x1024" self.image_url = response["data"][0]["url"]
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True self.processing, self.complete = False, True
``` ```
@ -220,6 +192,7 @@ We add a page from the root of the app to the index component. We also add a tit
```python ```python
app.add_page(index, title="DALL-E") app.add_page(index, title="DALL-E")
app.compile()
``` ```
You can create a multi-page app by adding more pages. You can create a multi-page app by adding more pages.
@ -228,16 +201,24 @@ You can create a multi-page app by adding more pages.
<div align="center"> <div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp; 📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div> </div>
## ✅ Status ## ✅ Status
Reflex launched in December 2022 with the name Pynecone. Reflex launched in December 2022 with the name Pynecone.
As of February 2024, our hosting service is in alpha! During this time anyone can deploy their apps for free. See our [roadmap](https://github.com/reflex-dev/reflex/issues/2727) to see what's planned. As of July 2023, we are in the **Public Beta** stage.
- :white_check_mark: **Public Alpha**: Anyone can install and use Reflex. There may be issues, but we are working to resolve them actively.
- :large_orange_diamond: **Public Beta**: Stable enough for non-enterprise use-cases.
- **Public Hosting Beta**: _Optionally_, deploy and host your apps on Reflex!
- **Public**: Reflex is production ready.
Reflex has new releases and features coming every week! Make sure to :star: star and :eyes: watch this repository to stay up to date. Reflex has new releases and features coming every week! Make sure to :star: star and :eyes: watch this repository to stay up to date.
@ -247,15 +228,9 @@ We welcome contributions of any size! Below are some good ways to get started in
- **Join Our Discord**: Our [Discord](https://discord.gg/T5WSbC2YtQ) is the best place to get help on your Reflex project and to discuss how you can contribute. - **Join Our Discord**: Our [Discord](https://discord.gg/T5WSbC2YtQ) is the best place to get help on your Reflex project and to discuss how you can contribute.
- **GitHub Discussions**: A great way to talk about features you want added or things that are confusing/need clarification. - **GitHub Discussions**: A great way to talk about features you want added or things that are confusing/need clarification.
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) are an excellent way to report bugs. Additionally, you can try and solve an existing issue and submit a PR. - **GitHub Issues**: These are an excellent way to report bugs. Additionally, you can try and solve an existing issue and submit a PR.
We are actively looking for contributors, no matter your skill level or experience. To contribute check out [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) We are actively looking for contributors, no matter your skill level or experience.
## All Thanks To Our Contributors:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## License ## License

View File

@ -1,3 +0,0 @@
"""Reflex benchmarks."""
WINDOWS_SKIP_REASON = "Takes too much time as a result of npm"

View File

@ -1,147 +0,0 @@
"""Extracts the compile times from the JSON files in the specified directory and inserts them into the database."""
from __future__ import annotations
import argparse
import json
import os
from pathlib import Path
from utils import send_data_to_posthog
def extract_stats_from_json(json_file: str) -> list[dict]:
"""Extracts the stats from the JSON data and returns them as a list of dictionaries.
Args:
json_file: The JSON file to extract the stats data from.
Returns:
list[dict]: The stats for each test.
"""
with Path(json_file).open() as file:
json_data = json.load(file)
# Load the JSON data if it is a string, otherwise assume it's already a dictionary
data = json.loads(json_data) if isinstance(json_data, str) else json_data
# Initialize an empty list to store the stats for each test
test_stats = []
# Iterate over each test in the 'benchmarks' list
for test in data.get("benchmarks", []):
group = test.get("group", None)
stats = test.get("stats", {})
full_name = test.get("fullname")
file_name = (
full_name.split("/")[-1].split("::")[0].strip(".py") if full_name else None
)
test_name = test.get("name", "Unknown Test")
test_stats.append(
{
"test_name": test_name,
"group": group,
"stats": stats,
"full_name": full_name,
"file_name": file_name,
}
)
return test_stats
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
performance_data: list[dict],
commit_sha: str,
pr_title: str,
branch_name: str,
event_type: str,
pr_id: str,
):
"""Insert the benchmarking data into the database.
Args:
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
performance_data: The performance data of reflex web to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
event_type: Type of github event(push, pull request, etc).
pr_id: Id of the PR.
"""
# Prepare the event data
properties = {
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"event_type": event_type,
"performance": performance_data,
"pr_id": pr_id,
}
send_data_to_posthog("simple_app_benchmark", properties)
def main():
"""Runs the benchmarks and inserts the results."""
# Get the commit SHA and JSON directory from the command line arguments
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--benchmark-json",
help="The JSON file containing the benchmark results.",
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--event-type",
help="The github event type",
required=True,
)
parser.add_argument(
"--pr-id",
help="ID of the PR.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
# Get the results of pytest benchmarks
cleaned_benchmark_results = extract_stats_from_json(args.benchmark_json)
# Insert the data into the database
insert_benchmarking_data(
os_type_version=args.os,
python_version=args.python_version,
performance_data=cleaned_benchmark_results,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
event_type=args.event_type,
pr_id=args.pr_id,
)
if __name__ == "__main__":
main()

View File

@ -1,128 +0,0 @@
"""Extract and upload benchmarking data to PostHog."""
from __future__ import annotations
import argparse
import json
import os
from pathlib import Path
from utils import send_data_to_posthog
def extract_stats_from_json(json_file: str) -> dict:
"""Extracts the stats from the JSON data and returns them as dictionaries.
Args:
json_file: The JSON file to extract the stats data from.
Returns:
dict: The stats for each test.
"""
with Path(json_file).open() as file:
json_data = json.load(file)
# Load the JSON data if it is a string, otherwise assume it's already a dictionary
data = json.loads(json_data) if isinstance(json_data, str) else json_data
result = data.get("results", [{}])[0]
return {
k: v
for k, v in result.items()
if k in ("mean", "stddev", "median", "min", "max")
}
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
performance_data: dict,
commit_sha: str,
pr_title: str,
branch_name: str,
pr_id: str,
app_name: str,
):
"""Insert the benchmarking data into the database.
Args:
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
performance_data: The imports performance data to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
pr_id: Id of the PR.
app_name: The name of the app being measured.
"""
properties = {
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"pr_id": pr_id,
"performance": performance_data,
"app_name": app_name,
}
send_data_to_posthog("import_benchmark", properties)
def main():
"""Runs the benchmarks and inserts the results."""
# Get the commit SHA and JSON directory from the command line arguments
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--benchmark-json",
help="The JSON file containing the benchmark results.",
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--app-name",
help="The name of the app measured.",
required=True,
)
parser.add_argument(
"--pr-id",
help="ID of the PR.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
cleaned_benchmark_results = extract_stats_from_json(args.benchmark_json)
# Insert the data into the database
insert_benchmarking_data(
os_type_version=args.os,
python_version=args.python_version,
performance_data=cleaned_benchmark_results,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
app_name=args.app_name,
pr_id=args.pr_id,
)
if __name__ == "__main__":
main()

View File

@ -1,75 +0,0 @@
"""Extracts the Lighthouse scores from the JSON files in the specified directory and inserts them into the database."""
from __future__ import annotations
import json
import sys
from pathlib import Path
from utils import send_data_to_posthog
def insert_benchmarking_data(
lighthouse_data: dict,
commit_sha: str,
):
"""Insert the benchmarking data into the database.
Args:
lighthouse_data: The Lighthouse data to insert.
commit_sha: The commit SHA to insert.
"""
properties = {
"distinct_id": commit_sha,
"lighthouse_data": lighthouse_data,
}
# Send the data to PostHog
send_data_to_posthog("lighthouse_benchmark", properties)
def get_lighthouse_scores(directory_path: str | Path) -> dict:
"""Extracts the Lighthouse scores from the JSON files in the specified directory.
Args:
directory_path (str): The path to the directory containing the JSON files.
Returns:
dict: The Lighthouse scores.
"""
scores = {}
directory_path = Path(directory_path)
try:
for filename in directory_path.iterdir():
if filename.suffix == ".json" and filename.stem != "manifest":
data = json.loads(filename.read_text())
# Extract scores and add them to the dictionary with the filename as key
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
"performance_score": data["categories"]["performance"]["score"],
"accessibility_score": data["categories"]["accessibility"]["score"],
"best_practices_score": data["categories"]["best-practices"][
"score"
],
"seo_score": data["categories"]["seo"]["score"],
}
except Exception as e:
return {"error": e}
return scores
def main():
"""Runs the benchmarks and inserts the results into the database."""
# Get the commit SHA and JSON directory from the command line arguments
commit_sha = sys.argv[1]
json_dir = sys.argv[2]
# Get the Lighthouse scores
lighthouse_scores = get_lighthouse_scores(json_dir)
# Insert the data into the database
insert_benchmarking_data(lighthouse_scores, commit_sha)
if __name__ == "__main__":
main()

View File

@ -1,135 +0,0 @@
"""Checks the size of a specific directory and uploads result to Posthog."""
import argparse
import os
from pathlib import Path
from utils import get_directory_size, get_python_version, send_data_to_posthog
def get_package_size(venv_path: Path, os_name):
"""Get the size of a specified package.
Args:
venv_path: The path to the venv.
os_name: Name of os.
Returns:
The total size of the package in bytes.
Raises:
ValueError: when venv does not exist or python version is None.
"""
python_version = get_python_version(venv_path, os_name)
print("Python version:", python_version)
if python_version is None:
raise ValueError("Error: Failed to determine Python version.")
is_windows = "windows" in os_name
package_dir: Path = (
venv_path / "lib" / f"python{python_version}" / "site-packages"
if not is_windows
else venv_path / "Lib" / "site-packages"
)
if not package_dir.exists():
raise ValueError(
"Error: Virtual environment does not exist or is not activated."
)
total_size = get_directory_size(package_dir)
return total_size
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
commit_sha: str,
pr_title: str,
branch_name: str,
pr_id: str,
path: str,
):
"""Insert the benchmarking data into PostHog.
Args:
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
pr_id: The id of the PR.
path: The path to the dir or file to check size.
"""
if "./dist" in path:
size = get_directory_size(Path(path))
else:
size = get_package_size(Path(path), os_type_version)
# Prepare the event data
properties = {
"path": path,
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"pr_id": pr_id,
"size_mb": round(
size / (1024 * 1024), 3
), # save size in MB and round to 3 places
}
send_data_to_posthog("package_size", properties)
def main():
"""Runs the benchmarks and inserts the results."""
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--pr-id",
help="The pr id",
required=True,
)
parser.add_argument(
"--path",
help="The path to the vnenv.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
# Insert the data into the database
insert_benchmarking_data(
os_type_version=args.os,
python_version=args.python_version,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
pr_id=args.pr_id,
path=args.path,
)
if __name__ == "__main__":
main()

View File

@ -1,106 +0,0 @@
"""Checks the size of a specific directory and uploads result to Posthog."""
import argparse
import os
from pathlib import Path
from utils import get_directory_size, send_data_to_posthog
def insert_benchmarking_data(
os_type_version: str,
python_version: str,
app_name: str,
commit_sha: str,
pr_title: str,
branch_name: str,
pr_id: str,
path: str,
):
"""Insert the benchmarking data into PostHog.
Args:
app_name: The name of the app being measured.
os_type_version: The OS type and version to insert.
python_version: The Python version to insert.
commit_sha: The commit SHA to insert.
pr_title: The PR title to insert.
branch_name: The name of the branch.
pr_id: The id of the PR.
path: The path to the dir or file to check size.
"""
size = get_directory_size(Path(path))
# Prepare the event data
properties = {
"app_name": app_name,
"os": os_type_version,
"python_version": python_version,
"distinct_id": commit_sha,
"pr_title": pr_title,
"branch_name": branch_name,
"pr_id": pr_id,
"size_mb": round(
size / (1024 * 1024), 3
), # save size in MB and round to 3 places
}
send_data_to_posthog("web-size", properties)
def main():
"""Runs the benchmarks and inserts the results."""
parser = argparse.ArgumentParser(description="Run benchmarks and process results.")
parser.add_argument(
"--os", help="The OS type and version to insert into the database."
)
parser.add_argument(
"--python-version", help="The Python version to insert into the database."
)
parser.add_argument(
"--commit-sha", help="The commit SHA to insert into the database."
)
parser.add_argument(
"--pr-title",
help="The PR title to insert into the database.",
)
parser.add_argument(
"--branch-name",
help="The current branch",
required=True,
)
parser.add_argument(
"--app-name",
help="The name of the app measured.",
required=True,
)
parser.add_argument(
"--pr-id",
help="The pr id",
required=True,
)
parser.add_argument(
"--path",
help="The current path to app to check.",
required=True,
)
args = parser.parse_args()
# Get the PR title from env or the args. For the PR merge or push event, there is no PR title, leaving it empty.
pr_title = args.pr_title or os.getenv("PR_TITLE", "")
# Insert the data into the database
insert_benchmarking_data(
app_name=args.app_name,
os_type_version=args.os,
python_version=args.python_version,
commit_sha=args.commit_sha,
pr_title=pr_title,
branch_name=args.branch_name,
pr_id=args.pr_id,
path=args.path,
)
if __name__ == "__main__":
main()

View File

@ -1,20 +0,0 @@
"""Shared conftest for all benchmark tests."""
import pytest
from reflex.testing import AppHarness, AppHarnessProd
@pytest.fixture(
scope="session", params=[AppHarness, AppHarnessProd], ids=["dev", "prod"]
)
def app_harness_env(request):
"""Parametrize the AppHarness class to use for the test, either dev or prod.
Args:
request: The pytest fixture request object.
Returns:
The AppHarness class to use for the test.
"""
return request.param

View File

@ -1,77 +0,0 @@
#!/bin/bash
# Change directory to the first argument passed to the script
project_dir=$1
shift
pushd "$project_dir" || exit 1
echo "Changed directory to $project_dir"
# So we get stdout / stderr from Python ASAP. Without this, delays can be very long (e.g. on Windows, Github Actions)
export PYTHONUNBUFFERED=1
env_mode=$1
shift
check_ports=${1:-3000 8000}
shift
# Start the server in the background
export TELEMETRY_ENABLED=false
reflex run --env "$env_mode" "$@" & pid=$!
# Within the context of this bash, $pid_in_bash is what we need to pass to "kill" on exit
# This is true on all platforms.
pid_in_bash=$pid
trap "kill -INT $pid_in_bash ||:" EXIT
echo "Started server with PID $pid"
# Assume we run from the root of the repo
popd
# In Windows, our Python script below needs to work with the WINPID
if [ -f /proc/$pid/winpid ]; then
pid=$(cat /proc/$pid/winpid)
echo "Windows detected, passing winpid $pid to port waiter"
fi
python scripts/wait_for_listening_port.py $check_ports --timeout=600 --server-pid "$pid"
# Check if something is running on port 3000
if curl --output /dev/null --silent --head --fail "http://localhost:3000"; then
echo "URL exists: http://localhost:3000"
else
echo "URL does not exist: https://localhost:3000"
fi
mkdir -p ./tests/benchmarks/.lighthouseci
# Create a lighthouserc.js file
cat << EOF > lighthouserc.js
module.exports = {
ci: {
collect: {
isSinglePageApplication: true,
numberOfRuns: 1,
url: ['http://localhost:3000', "http://localhost:3000/docs/getting-started/introduction/", "http://localhost:3000/blog/2023-08-02-seed-annoucement/"]
},
upload: {
target: 'filesystem',
"outputDir": "./integration/benchmarks/.lighthouseci"
},
},
};
EOF
# Install and Run LHCI
npm install -g @lhci/cli
lhci autorun
# Check to see if the LHCI report is generated
if [ -d "./integration/benchmarks/.lighthouseci" ] && [ "$(ls -A ./integration/benchmarks/.lighthouseci)" ]; then
echo "LHCI report generated"
else
echo "LHCI report not generated"
exit 1 # Exits the script with a status of 1, which will cause the GitHub Action to stop
fi

View File

@ -1,74 +0,0 @@
"""Utility functions for the benchmarks."""
import os
import subprocess
from pathlib import Path
import httpx
from httpx import HTTPError
def get_python_version(venv_path: Path, os_name):
"""Get the python version of python in a virtual env.
Args:
venv_path: Path to virtual environment.
os_name: Name of os.
Returns:
The python version.
"""
python_executable = (
venv_path / "bin" / "python"
if "windows" not in os_name
else venv_path / "Scripts" / "python.exe"
)
try:
output = subprocess.check_output(
[str(python_executable), "--version"], stderr=subprocess.STDOUT
)
python_version = output.decode("utf-8").strip().split()[1]
return ".".join(python_version.split(".")[:-1])
except subprocess.CalledProcessError:
return None
def get_directory_size(directory: Path):
"""Get the size of a directory in bytes.
Args:
directory: The directory to check.
Returns:
The size of the dir in bytes.
"""
total_size = 0
for dirpath, _, filenames in os.walk(directory):
for f in filenames:
fp = Path(dirpath) / f
total_size += fp.stat().st_size
return total_size
def send_data_to_posthog(event, properties):
"""Send data to PostHog.
Args:
event: The event to send.
properties: The properties to send.
Raises:
HTTPError: When there is an error sending data to PostHog.
"""
event_data = {
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb",
"event": event,
"properties": properties,
}
with httpx.Client() as client:
response = client.post("https://app.posthog.com/capture/", json=event_data)
if response.status_code != 200:
raise HTTPError(
f"Error sending data to PostHog: {response.status_code} - {response.text}"
)

View File

@ -0,0 +1,2 @@
.web
__pycache__/*

18
docker-example/Caddyfile Normal file
View File

@ -0,0 +1,18 @@
{$DOMAIN}
encode gzip
@backend_routes path /event/* /upload /ping
handle @backend_routes {
reverse_proxy app:8000
}
route {
try_files {path} {path}.html
file_server {
root /srv
pass_thru
}
# proxy dynamic routes to nextjs server
reverse_proxy app:3000
}

38
docker-example/Dockerfile Normal file
View File

@ -0,0 +1,38 @@
# Stage 1: init
FROM python:3.11 as init
# Pass `--build-arg API_URL=http://app.example.com:8000` during build
ARG API_URL
# Copy local context to `/app` inside container (see .dockerignore)
WORKDIR /app
COPY . .
# Reflex will install bun, nvm, and node to `$HOME/.reflex` (/app/.reflex)
ENV HOME=/app
# Create virtualenv which will be copied into final container
ENV VIRTUAL_ENV=/app/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN python3 -m venv $VIRTUAL_ENV
# Install app requirements and reflex inside virtualenv
RUN pip install -r requirements.txt
# Deploy templates and prepare app
RUN reflex init
# Export static copy of frontend to /app/.web/_static (and pre-install frontend packages)
RUN reflex export --frontend-only --no-zip
# Stage 2: copy artifacts into slim image
FROM python:3.11-slim
ARG API_URL
WORKDIR /app
RUN adduser --disabled-password --home /app reflex
COPY --chown=reflex --from=init /app /app
USER reflex
ENV PATH="/app/.venv/bin:$PATH" API_URL=$API_URL
CMD reflex db migrate && reflex run --env prod

View File

@ -1,30 +1,66 @@
# Reflex Docker Examples # Reflex Docker Container
This directory contains several examples of how to deploy Reflex apps using docker. This example describes how to create and use a container image for Reflex with your own code.
In all cases, ensure that your `requirements.txt` file is up to date and ## Update Requirements
includes the `reflex` package.
## `simple-two-port` The `requirements.txt` includes the reflex package which is needed to install
Reflex framework. If you use additional packages in your project you have to add
this in the `requirements.txt` first. Copy the `Dockerfile`, `.dockerignore` and
the `requirements.txt` file in your project folder.
The most basic production deployment exposes two HTTP ports and relies on an ## Build Reflex Container Image
existing load balancer to forward the traffic appropriately.
## `simple-one-port` To build your container image run the following command:
This deployment exports the frontend statically and serves it via a single HTTP ```bash
port using Caddy. This is useful for platforms that only support a single port docker build -t reflex-app:latest . --build-arg API_URL=http://app.example.com:8000
or where running a node server in the container is undesirable. ```
## `production-compose` Ensure that `API_URL` is set to the publicly accessible hostname or IP where the app
will be hosted.
This deployment is intended for use with a standalone VPS that is only hosting a ## Start Container Service
single Reflex app. It provides the entire stack in a single `compose.yaml`
including a webserver, one or more backend instances, redis, and a postgres
database.
## `production-app-platform` Finally, you can start your Reflex container service as follows:
This example deployment is intended for use with App hosting platforms, like ```bash
Azure, AWS, or Google Cloud Run. It is the backend of the deployment, which docker run -p 3000:3000 -p 8000:8000 --name app reflex-app:latest
depends on a separately hosted redis instance and static frontend deployment. ```
It may take a few seconds for the service to become available.
# Production Service with Docker Compose and Caddy
An example production deployment uses automatic TLS with Caddy serving static files
for the frontend and proxying requests to both the frontend and backend.
Copy `compose.yaml`, `Caddy.Dockerfile` and `Caddyfile` to your project directory. The production
build leverages the same `Dockerfile` described above.
## Customize `Caddyfile`
If the app uses additional backend API routes, those should be added to the
`@backend_routes` path matcher to ensure they are forwarded to the backend.
## Build Reflex Production Service
During build, set `DOMAIN` environment variable to the domain where the app will
be hosted! (Do not include http or https, it will always use https)
```bash
DOMAIN=example.com docker compose build
```
This will build both the `app` service from the existing `Dockerfile` and the `webserver`
service via `Caddy.Dockerfile` that copies the `Caddyfile` and static frontend export
from the `app` service into the container.
## Run Reflex Production Service
```bash
DOMAIN=example.com docker compose up
```
The app should be available at the specified domain via HTTPS. Certificate
provisioning will occur automatically and may take a few minutes.

View File

@ -0,0 +1,21 @@
# During build and run, set environment DOMAIN pointing
# to publicly accessible domain where app will be hosted
services:
app:
image: local/reflex-app
build:
context: .
args:
API_URL: https://${DOMAIN:-localhost}
webserver:
environment:
DOMAIN: ${DOMAIN:-localhost}
ports:
- 443:443
- 80:80 # for acme-challenge via HTTP
build:
context: .
dockerfile: Caddy.Dockerfile
depends_on:
- app

View File

@ -1,5 +0,0 @@
.web
.git
__pycache__/*
Dockerfile
uploaded_files

View File

@ -1,65 +0,0 @@
# This docker file is intended to be used with container hosting services
#
# After deploying this image, get the URL pointing to the backend service
# and run API_URL=https://path-to-my-container.example.com reflex export frontend
# then copy the contents of `frontend.zip` to your static file server (github pages, s3, etc).
#
# Azure Static Web App example:
# npx @azure/static-web-apps-cli deploy --env production --app-location .web/_static
#
# For dynamic routes to function properly, ensure that 404s are redirected to /404 on the
# static file host (for github pages, this works out of the box; remember to create .nojekyll).
#
# For azure static web apps, add `staticwebapp.config.json` to to `.web/_static` with the following:
# {
# "responseOverrides": {
# "404": {
# "rewrite": "/404.html"
# }
# }
# }
#
# Note: many container hosting platforms require amd64 images, so when building on an M1 Mac
# for example, pass `docker build --platform=linux/amd64 ...`
# Stage 1: init
FROM python:3.13 as init
ARG uv=/root/.local/bin/uv
# Install `uv` for faster package bootstrapping
ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh
RUN /install.sh && rm /install.sh
# Copy local context to `/app` inside container (see .dockerignore)
WORKDIR /app
COPY . .
RUN mkdir -p /app/data /app/uploaded_files
# Create virtualenv which will be copied into final container
ENV VIRTUAL_ENV=/app/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN $uv venv
# Install app requirements and reflex inside virtualenv
RUN $uv pip install -r requirements.txt
# Deploy templates and prepare app
RUN reflex init
# Stage 2: copy artifacts into slim image
FROM python:3.13-slim
WORKDIR /app
RUN adduser --disabled-password --home /app reflex
COPY --chown=reflex --from=init /app /app
# Install libpq-dev for psycopg (skip if not using postgres).
RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/*
USER reflex
ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
# Always apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
exec reflex run --env prod --backend-only --backend-port ${PORT:-8000}

View File

@ -1,113 +0,0 @@
# production-app-platform
This example deployment is intended for use with App hosting platforms, like
Azure, AWS, or Google Cloud Run.
## Architecture
The production deployment consists of a few pieces:
* Backend container - built by `Dockerfile` Runs the Reflex backend
service on port 8000 and is scalable to multiple instances.
* Redis container - A single instance the standard `redis` docker image should
share private networking with the backend
* Static frontend - HTML/CSS/JS files that are hosted via a CDN or static file
server. This is not included in the docker image.
## Deployment
These general steps do not cover the specifics of each platform, but all platforms should
support the concepts described here.
### Vnet
All containers in the deployment should be hooked up to the same virtual private
network so they can access the redis service and optionally the database server.
The vnet should not be exposed to the internet, use an ingress rule to terminate
TLS at the load balancer and forward the traffic to a backend service replica.
### Redis
Deploy a `redis` instance on the vnet.
### Backend
The backend is built by the `Dockerfile` in this directory. When deploying the
backend, be sure to set REDIS_URL=redis://internal-redis-hostname to connect to
the redis service.
### Ingress
Configure the load balancer for the app to forward traffic to port 8000 on the
backend service replicas. Most platforms will generate an ingress hostname
automatically. Make sure when you access the ingress endpoint on `/ping` that it
returns "pong", indicating that the backend is up an available.
### Frontend
The frontend should be hosted on a static file server or CDN.
**Important**: when exporting the frontend, set the API_URL environment variable
to the ingress hostname of the backend service.
If you will host the frontend from a path other than the root, set the
`FRONTEND_PATH` environment variable appropriately when exporting the frontend.
Most static hosts will automatically use the `/404.html` file to handle 404
errors. _This is essential for dynamic routes to work correctly._ Ensure that
missing routes return the `/404.html` content to the user if this is not the
default behavior.
_For Github Pages_: ensure the file `.nojekyll` is present in the root of the repo
to avoid special processing of underscore-prefix directories, like `_next`.
## Platform Notes
The following sections are currently a work in progress and may be incomplete.
### Azure
In the Azure load balancer, per-message deflate is not supported. Add the following
to your `rxconfig.py` to workaround this issue.
```python
import uvicorn.workers
import reflex as rx
class NoWSPerMessageDeflate(uvicorn.workers.UvicornH11Worker):
CONFIG_KWARGS = {
**uvicorn.workers.UvicornH11Worker.CONFIG_KWARGS,
"ws_per_message_deflate": False,
}
config = rx.Config(
app_name="my_app",
gunicorn_worker_class="rxconfig.NoWSPerMessageDeflate",
)
```
#### Persistent Storage
If you need to use a database or upload files, you cannot save them to the
container volume. Use Azure Files and mount it into the container at /app/uploaded_files.
#### Resource Types
* Create a new vnet with 10.0.0.0/16
* Create a new subnet for redis, database, and containers
* Deploy redis as a Container Instances
* Deploy database server as "Azure Database for PostgreSQL"
* Create a new database for the app
* Set db-url as a secret containing the db user/password connection string
* Deploy Storage account for uploaded files
* Enable access from the vnet and container subnet
* Create a new file share
* In the environment, create a new files share (get the storage key)
* Deploy the backend as a Container App
* Create a custom Container App Environment linked up to the same vnet as the redis container.
* Set REDIS_URL and DB_URL environment variables
* Add the volume from the environment
* Add the volume mount to the container
* Deploy the frontend as a Static Web App

View File

@ -1,8 +0,0 @@
.web
.git
__pycache__/*
Dockerfile
Caddy.Dockerfile
compose.yaml
compose.*.yaml
uploaded_files

View File

@ -1,14 +0,0 @@
{$DOMAIN}
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy app:8000
}
root * /srv
route {
try_files {path} {path}/ /404.html
file_server
}

View File

@ -1,52 +0,0 @@
# This docker file is intended to be used with docker compose to deploy a production
# instance of a Reflex app.
# Stage 1: init
FROM python:3.13 as init
ARG uv=/root/.local/bin/uv
# Install `uv` for faster package bootstrapping
ADD --chmod=755 https://astral.sh/uv/install.sh /install.sh
RUN /install.sh && rm /install.sh
# Copy local context to `/app` inside container (see .dockerignore)
WORKDIR /app
COPY . .
RUN mkdir -p /app/data /app/uploaded_files
# Create virtualenv which will be copied into final container
ENV VIRTUAL_ENV=/app/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN $uv venv
# Install app requirements and reflex inside virtualenv
RUN $uv pip install -r requirements.txt
# Deploy templates and prepare app
RUN reflex init
# Export static copy of frontend to /app/.web/_static
RUN reflex export --frontend-only --no-zip
# Copy static files out of /app to save space in backend image
RUN mv .web/_static /tmp/_static
RUN rm -rf .web && mkdir .web
RUN mv /tmp/_static .web/_static
# Stage 2: copy artifacts into slim image
FROM python:3.13-slim
WORKDIR /app
RUN adduser --disabled-password --home /app reflex
COPY --chown=reflex --from=init /app /app
# Install libpq-dev for psycopg (skip if not using postgres).
RUN apt-get update -y && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/*
USER reflex
ENV PATH="/app/.venv/bin:$PATH" PYTHONUNBUFFERED=1
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
# Always apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
exec reflex run --env prod --backend-only

View File

@ -1,75 +0,0 @@
# production-compose
This example production deployment uses automatic TLS with Caddy serving static
files for the frontend and proxying requests to both the frontend and backend.
It is intended for use with a standalone VPS that is only hosting a single
Reflex app.
The production app container (`Dockerfile`), builds and exports the frontend
statically (to be served by Caddy). The resulting image only runs the backend
service.
The `webserver` service, based on `Caddy.Dockerfile`, copies the static frontend
and `Caddyfile` into the container to configure the reverse proxy routes that will
forward requests to the backend service. Caddy will automatically provision TLS
for localhost or the domain specified in the environment variable `DOMAIN`.
This type of deployment should use less memory and be more performant since
nodejs is not required at runtime.
## Customize `Caddyfile` (optional)
If the app uses additional backend API routes, those should be added to the
`@backend_routes` path matcher to ensure they are forwarded to the backend.
## Build Reflex Production Service
During build, set `DOMAIN` environment variable to the domain where the app will
be hosted! (Do not include http or https, it will always use https).
**If `DOMAIN` is not provided, the service will default to `localhost`.**
```bash
DOMAIN=example.com docker compose build
```
This will build both the `app` service from the `prod.Dockerfile` and the `webserver`
service via `Caddy.Dockerfile`.
## Run Reflex Production Service
```bash
DOMAIN=example.com docker compose up
```
The app should be available at the specified domain via HTTPS. Certificate
provisioning will occur automatically and may take a few minutes.
### Data Persistence
Named docker volumes are used to persist the app database (`db-data`),
uploaded_files (`upload-data`), and caddy TLS keys and certificates
(`caddy-data`).
## More Robust Deployment
For a more robust deployment, consider bringing the service up with
`compose.prod.yaml` which includes postgres database and redis cache, allowing
the backend to run with multiple workers and service more requests.
```bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml up -d
```
Postgres uses its own named docker volume for data persistence.
## Admin Tools
When needed, the services in `compose.tools.yaml` can be brought up, providing
graphical database administration (Adminer on http://localhost:8080) and a
redis cache browser (redis-commander on http://localhost:8081). It is not recommended
to deploy these services if they are not in active use.
```bash
DOMAIN=example.com docker compose -f compose.yaml -f compose.prod.yaml -f compose.tools.yaml up -d
```

View File

@ -1,25 +0,0 @@
# Use this override file to run the app in prod mode with postgres and redis
# docker compose -f compose.yaml -f compose.prod.yaml up -d
services:
db:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: secret
volumes:
- postgres-data:/var/lib/postgresql/data
redis:
image: redis
restart: always
app:
environment:
DB_URL: postgresql+psycopg://postgres:secret@db/postgres
REDIS_URL: redis://redis:6379
depends_on:
- db
- redis
volumes:
postgres-data:

View File

@ -1,18 +0,0 @@
# Use this override file with `compose.prod.yaml` to run admin tools
# for production services.
# docker compose -f compose.yaml -f compose.prod.yaml -f compose.tools.yaml up -d
services:
adminer:
image: adminer
ports:
- 8080:8080
redis-commander:
image: ghcr.io/joeferner/redis-commander:latest
environment:
- REDIS_HOSTS=local:redis:6379
ports:
- "8081:8081"
volumes:
redis-ui-settings:

View File

@ -1,41 +0,0 @@
# Base compose file production deployment of reflex app with Caddy webserver
# providing TLS termination and reverse proxying.
#
# See `compose.prod.yaml` for more robust and performant deployment option.
#
# During build and run, set environment DOMAIN pointing
# to publicly accessible domain where app will be hosted
services:
app:
image: local/reflex-app
environment:
DB_URL: sqlite:///data/reflex.db
build:
context: .
volumes:
- db-data:/app/data
- upload-data:/app/uploaded_files
restart: always
webserver:
environment:
DOMAIN: ${DOMAIN:-localhost}
ports:
- 443:443
- 80:80 # For acme-challenge via HTTP.
build:
context: .
dockerfile: Caddy.Dockerfile
volumes:
- caddy-data:/root/.caddy
restart: always
depends_on:
- app
volumes:
# SQLite data
db-data:
# Uploaded files
upload-data:
# TLS keys and certificates
caddy-data:

View File

@ -1,3 +0,0 @@
.web
!.web/bun.lockb
!.web/package.json

View File

@ -1,14 +0,0 @@
:{$PORT}
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
root * /srv
route {
try_files {path} {path}/ /404.html
file_server
}

View File

@ -1,62 +0,0 @@
# This Dockerfile is used to deploy a single-container Reflex app instance
# to services like Render, Railway, Heroku, GCP, and others.
# If the service expects a different port, provide it here (f.e Render expects port 10000)
ARG PORT=8080
# Only set for local/direct access. When TLS is used, the API_URL is assumed to be the same as the frontend.
ARG API_URL
# It uses a reverse proxy to serve the frontend statically and proxy to backend
# from a single exposed port, expecting TLS termination to be handled at the
# edge by the given platform.
FROM python:3.13 as builder
RUN mkdir -p /app/.web
RUN python -m venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
WORKDIR /app
# Install python app requirements and reflex in the container
COPY requirements.txt .
RUN pip install -r requirements.txt
# Install reflex helper utilities like bun/fnm/node
COPY rxconfig.py ./
RUN reflex init
# Install pre-cached frontend dependencies (if exist)
COPY *.web/bun.lockb *.web/package.json .web/
RUN if [ -f .web/bun.lockb ]; then cd .web && ~/.local/share/reflex/bun/bin/bun install --frozen-lockfile; fi
# Copy local context to `/app` inside container (see .dockerignore)
COPY . .
ARG PORT API_URL
# Download other npm dependencies and compile frontend
RUN API_URL=${API_URL:-http://localhost:$PORT} reflex export --loglevel debug --frontend-only --no-zip && mv .web/_static/* /srv/ && rm -rf .web
# Final image with only necessary files
FROM python:3.13-slim
# Install Caddy and redis server inside image
RUN apt-get update -y && apt-get install -y caddy redis-server && rm -rf /var/lib/apt/lists/*
ARG PORT API_URL
ENV PATH="/app/.venv/bin:$PATH" PORT=$PORT API_URL=${API_URL:-http://localhost:$PORT} REDIS_URL=redis://localhost PYTHONUNBUFFERED=1
WORKDIR /app
COPY --from=builder /app /app
COPY --from=builder /srv /srv
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
EXPOSE $PORT
# Apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
caddy start && \
redis-server --daemonize yes && \
exec reflex run --env prod --backend-only

View File

@ -1,37 +0,0 @@
# production-one-port
This docker deployment runs Reflex in prod mode, exposing a single HTTP port:
* `8080` (`$PORT`) - Caddy server hosting the frontend statically and proxying requests to the backend.
The deployment also runs a local Redis server to store state for each user.
Conceptually it is similar to the `simple-one-port` example except it:
* has layer caching for python, reflex, and node dependencies
* uses multi-stage build to reduce the size of the final image
Using this method may be preferable for deploying in memory constrained
environments, because it serves a static frontend export, rather than running
the NextJS server via node.
## Build
```console
docker build -t reflex-production-one-port .
```
## Run
```console
docker run -p 8080:8080 reflex-production-one-port
```
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
## Usage
This container should be used with an existing load balancer or reverse proxy to
terminate TLS.
It is also useful for deploying to simple app platforms, such as Render or Heroku.

View File

@ -0,0 +1 @@
reflex

View File

@ -1,5 +0,0 @@
.web
.git
__pycache__/*
Dockerfile
uploaded_files

View File

@ -1,14 +0,0 @@
:{$PORT}
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
root * /srv
route {
try_files {path} {path}/ /404.html
file_server
}

View File

@ -1,41 +0,0 @@
# This Dockerfile is used to deploy a single-container Reflex app instance
# to services like Render, Railway, Heroku, GCP, and others.
# It uses a reverse proxy to serve the frontend statically and proxy to backend
# from a single exposed port, expecting TLS termination to be handled at the
# edge by the given platform.
FROM python:3.13
# If the service expects a different port, provide it here (f.e Render expects port 10000)
ARG PORT=8080
# Only set for local/direct access. When TLS is used, the API_URL is assumed to be the same as the frontend.
ARG API_URL
ENV PORT=$PORT API_URL=${API_URL:-http://localhost:$PORT} REDIS_URL=redis://localhost PYTHONUNBUFFERED=1
# Install Caddy and redis server inside image
RUN apt-get update -y && apt-get install -y caddy redis-server && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy local context to `/app` inside container (see .dockerignore)
COPY . .
# Install app requirements and reflex in the container
RUN pip install -r requirements.txt
# Deploy templates and prepare app
RUN reflex init
# Download all npm dependencies and compile frontend
RUN reflex export --frontend-only --no-zip && mv .web/_static/* /srv/ && rm -rf .web
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
EXPOSE $PORT
# Apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
caddy start && \
redis-server --daemonize yes && \
exec reflex run --env prod --backend-only

View File

@ -1,36 +0,0 @@
# simple-one-port
This docker deployment runs Reflex in prod mode, exposing a single HTTP port:
* `8080` (`$PORT`) - Caddy server hosting the frontend statically and proxying requests to the backend.
The deployment also runs a local Redis server to store state for each user.
Using this method may be preferable for deploying in memory constrained
environments, because it serves a static frontend export, rather than running
the NextJS server via node.
For platforms which only terminate TLS to a single port, this container can be
deployed instead of the `simple-two-port` example.
## Build
```console
docker build -t reflex-simple-one-port .
```
## Run
```console
docker run -p 8080:8080 reflex-simple-one-port
```
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
## Usage
This container should be used with an existing load balancer or reverse proxy to
terminate TLS.
It is also useful for deploying to simple app platforms, such as Render or Heroku.

View File

@ -1,5 +0,0 @@
.web
.git
__pycache__/*
Dockerfile
uploaded_files

View File

@ -1,26 +0,0 @@
# This Dockerfile is used to deploy a simple single-container Reflex app instance.
FROM python:3.13
RUN apt-get update && apt-get install -y redis-server && rm -rf /var/lib/apt/lists/*
ENV REDIS_URL=redis://localhost PYTHONUNBUFFERED=1
# Copy local context to `/app` inside container (see .dockerignore)
WORKDIR /app
COPY . .
# Install app requirements and reflex in the container
RUN pip install -r requirements.txt
# Deploy templates and prepare app
RUN reflex init
# Download all npm dependencies and compile frontend
RUN reflex export --frontend-only --no-zip
# Needed until Reflex properly passes SIGTERM on backend.
STOPSIGNAL SIGKILL
# Always apply migrations before starting the backend.
CMD [ -d alembic ] && reflex db migrate; \
redis-server --daemonize yes && \
exec reflex run --env prod

View File

@ -1,44 +0,0 @@
# simple-two-port
This docker deployment runs Reflex in prod mode, exposing two HTTP ports:
* `3000` - node NextJS server using optimized production build
* `8000` - python gunicorn server hosting the Reflex backend
The deployment also runs a local Redis server to store state for each user.
## Build
```console
docker build -t reflex-simple-two-port .
```
## Run
```console
docker run -p 3000:3000 -p 8000:8000 reflex-simple-two-port
```
Note that this container has _no persistence_ and will lose all data when
stopped. You can use bind mounts or named volumes to persist the database and
uploaded_files directories as needed.
## Usage
This container should be used with an existing load balancer or reverse proxy to
route traffic to the appropriate port inside the container.
For example, the following Caddyfile can be used to terminate TLS and forward
traffic to the frontend and backend from outside the container.
```
my-domain.com
encode gzip
@backend_routes path /_event/* /ping /_upload /_upload/*
handle @backend_routes {
reverse_proxy localhost:8000
}
reverse_proxy localhost:3000
```

View File

@ -1,28 +0,0 @@
# Debugging
It is possible to run Reflex apps in dev mode under a debugger.
1. Run Reflex as a module: `python -m reflex run --env dev`
2. Set current working directory to the dir containing `rxconfig.py`
## VSCode
The following launch configuration can be used to interactively debug a Reflex
app with breakpoints.
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Reflex App",
"type": "python",
"request": "launch",
"module": "reflex",
"args": "run --env dev",
"justMyCode": true,
"cwd": "${fileDirname}/.."
}
]
}
```

View File

@ -1,261 +0,0 @@
```diff
+ Suchst du nach Pynecone? Dann bist du hier in der richtigen Repository. Pynecone wurde in Reflex umbenannt. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Performante, anpassbare Web-Apps in purem Python. Bereitstellung in Sekunden. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex ist eine Bibliothek, mit der man Full-Stack-Web-Applikationen in purem Python erstellen kann.
Wesentliche Merkmale:
* **Pures Python** - Schreibe dein Front- und Backend in Python, es gibt also keinen Grund, JavaScript zu lernen.
* **Volle Flexibilität** - Reflex ist einfach zu handhaben, kann aber auch für komplexe Anwendungen skaliert werden.
* **Sofortige Bereitstellung** - Nach dem Erstellen kannst du deine App mit einem [einzigen Befehl](https://reflex.dev/docs/hosting/deploy-quick-start/) bereitstellen oder auf deinem eigenen Server hosten.
Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) erfahren Sie, wie Reflex unter der Haube funktioniert.
## ⚙️ Installation
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.10+):
```bash
pip install reflex
```
## 🥳 Erstelle deine erste App
Die Installation von `reflex` installiert auch das `reflex`-Kommandozeilen-Tool.
Teste, ob die Installation erfolgreich war, indem du ein neues Projekt erstellst. (Ersetze `my_app_name` durch deinen Projektnamen):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Dieser Befehl initialisiert eine Vorlage in deinem neuen Verzeichnis.
Du kannst diese App im Entwicklungsmodus ausführen:
```bash
reflex run
```
Du solltest deine App unter http://localhost:3000 laufen sehen.
Nun kannst du den Quellcode in `my_app_name/my_app_name.py` ändern. Reflex hat schnelle Aktualisierungen, sodass du deine Änderungen sofort siehst, wenn du deinen Code speicherst.
## 🫧 Beispiel-App
Lass uns ein Beispiel durchgehen: die Erstellung einer Benutzeroberfläche für die Bildgenerierung mit [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Zur Vereinfachung rufen wir einfach die [OpenAI-API](https://platform.openai.com/docs/api-reference/authentication) auf, aber du könntest dies auch durch ein lokal ausgeführtes ML-Modell ersetzen.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="Eine Benutzeroberfläche für DALL·E, die im Prozess der Bildgenerierung gezeigt wird." width="550" />
</div>
&nbsp;
Hier ist der komplette Code, um dies zu erstellen. Das alles wird in einer Python-Datei gemacht!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""Der Zustand der App."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Hole das Bild aus dem Prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Füge Zustand und Seite zur App hinzu.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## Schauen wir uns das mal genauer an.
<div align="center">
<img src="docs/images/dalle_colored_code_example.png" alt="Erläuterung der Unterschiede zwischen Backend- und Frontend-Teilen der DALL-E-App." width="900" />
</div>
### **Reflex-UI**
Fangen wir mit der Benutzeroberfläche an.
```python
def index():
return rx.center(
...
)
```
Diese `index`-Funktion definiert das Frontend der App.
Wir verwenden verschiedene Komponenten wie `center`, `vstack`, `input` und `button`, um das Frontend zu erstellen. Komponenten können ineinander verschachtelt werden, um komplexe Layouts zu erstellen. Und du kannst Schlüsselwortargumente verwenden, um sie mit der vollen Kraft von CSS zu stylen.
Reflex wird mit [über 60 eingebauten Komponenten](https://reflex.dev/docs/library) geliefert, die dir den Einstieg erleichtern. Wir fügen aktiv weitere Komponenten hinzu, und es ist einfach, [eigene Komponenten zu erstellen](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
Reflex stellt deine Benutzeroberfläche als Funktion deines Zustands dar.
```python
class State(rx.State):
"""Der Zustand der App."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Der Zustand definiert alle Variablen (genannt Vars) in einer App, die sich ändern können, und die Funktionen, die sie ändern.
Hier besteht der Zustand aus einem `prompt` und einer `image_url`. Es gibt auch die Booleans `processing` und `complete`, um anzuzeigen, wann der Button deaktiviert werden soll (während der Bildgenerierung) und wann das resultierende Bild angezeigt werden soll.
### **Event-Handler**
```python
def get_image(self):
"""Hole das Bild aus dem Prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Innerhalb des Zustands definieren wir Funktionen, die als Event-Handler bezeichnet werden und die Zustand-Variablen ändern. Event-Handler sind die Art und Weise, wie wir den Zustand in Reflex ändern können. Sie können als Reaktion auf Benutzeraktionen aufgerufen werden, z.B. beim Klicken auf eine Schaltfläche oder bei der Eingabe in ein Textfeld. Diese Aktionen werden als Ereignisse bezeichnet.
Unsere DALL-E.-App hat einen Event-Handler, `get_image`, der dieses Bild von der OpenAI-API abruft. Die Verwendung von `yield` in der Mitte eines Event-Handlers führt zu einer Aktualisierung der Benutzeroberfläche. Andernfalls wird die Benutzeroberfläche am Ende des Ereignishandlers aktualisiert.
### **Routing**
Schließlich definieren wir unsere App.
```python
app = rx.App()
```
Wir fügen der Indexkomponente eine Seite aus dem Stammverzeichnis der Anwendung hinzu. Wir fügen auch einen Titel hinzu, der in der Seitenvorschau/Browser-Registerkarte angezeigt wird.
```python
app.add_page(index, title="DALL-E")
```
Du kannst eine mehrseitige App erstellen, indem du weitere Seiten hinzufügst.
## 📑 Ressourcen
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Komponentenbibliothek](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Galerie](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Bereitstellung](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Status
Reflex wurde im Dezember 2022 unter dem Namen Pynecone gestartet.
Ab Februar 2024 befindet sich unser Hosting-Service in der Alpha-Phase! In dieser Zeit kann jeder seine Apps kostenlos bereitstellen. Siehe unsere [Roadmap](https://github.com/reflex-dev/reflex/issues/2727), um zu sehen, was geplant ist.
Reflex hat wöchentliche Veröffentlichungen und neue Features! Stelle sicher, dass du dieses Repository mit einem :star: Stern markierst und :eyes: beobachtest, um auf dem Laufenden zu bleiben.
## Beitragende
Wir begrüßen Beiträge jeder Größe! Hier sind einige gute Möglichkeiten, um in der Reflex-Community zu starten.
- **Tritt unserem Discord bei**: Unser [Discord](https://discord.gg/T5WSbC2YtQ) ist der beste Ort, um Hilfe für dein Reflex-Projekt zu bekommen und zu besprechen, wie du beitragen kannst.
- **GitHub-Diskussionen**: Eine großartige Möglichkeit, über Funktionen zu sprechen, die du hinzugefügt haben möchtest oder Dinge, die verwirrend sind/geklärt werden müssen.
- **GitHub-Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) sind eine ausgezeichnete Möglichkeit, Bugs zu melden. Außerdem kannst du versuchen, ein bestehendes Problem zu lösen und eine PR einzureichen.
Wir suchen aktiv nach Mitwirkenden, unabhängig von deinem Erfahrungslevel oder deiner Erfahrung. Um beizutragen, sieh dir [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) an.
## Vielen Dank an unsere Mitwirkenden:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## Lizenz
Reflex ist Open-Source und lizenziert unter der [Apache License 2.0](LICENSE).

View File

@ -1,246 +0,0 @@
```diff
+ ¿Buscando Pynecone? Estás en el repositorio correcto. Pynecone ha sido renombrado a Reflex. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Aplicaciones web personalizables y eficaces en Python puro. Despliega tu aplicación en segundos. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![Pruebas](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![Versiones](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentación](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex es una biblioteca para construir aplicaciones web full-stack en Python puro.
Características clave:
* **Python puro** - Escribe el frontend y backend de tu aplicación en Python, sin necesidad de aprender JavaScript.
* **Flexibilidad total** - Reflex es fácil para empezar, pero también puede escalar a aplicaciones complejas.
* **Despliegue instantáneo** - Después de construir, despliega tu aplicación con un [solo comando](https://reflex.dev/docs/hosting/deploy-quick-start/) u hospédala en tu propio servidor.
Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) para aprender cómo funciona Reflex en detalle.
## ⚙️ Instalación
Abra un terminal y ejecute (Requiere Python 3.10+):
```bash
pip install reflex
```
## 🥳 Crea tu primera aplicación
Al instalar `reflex` también se instala la herramienta de línea de comandos `reflex`.
Compruebe que la instalación se ha realizado correctamente creando un nuevo proyecto. (Sustituye `my_app_name` por el nombre de tu proyecto):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Este comando inicializa una plantilla en tu nuevo directorio.
Puedes iniciar esta aplicación en modo de desarrollo:
```bash
reflex run
```
Debería ver su aplicación ejecutándose en http://localhost:3000.
Ahora puede modificar el código fuente en `my_app_name/my_app_name.py`. Reflex se actualiza rápidamente para que pueda ver los cambios al instante cuando guarde el código.
## 🫧 Ejemplo de una Aplicación
Veamos un ejemplo: crearemos una UI de generación de imágenes en torno a [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Para simplificar, solo llamamos a la [API de OpenAI](https://platform.openai.com/docs/api-reference/authentication), pero podrías reemplazar esto con un modelo ML ejecutado localmente.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="Un envoltorio frontend para DALL·E, mostrado en el proceso de generar una imagen." width="550" />
</div>
&nbsp;
Aquí está el código completo para crear esto. ¡Todo esto se hace en un archivo de Python!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""El estado de la aplicación"""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Obtiene la imagen desde la consulta."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Agrega el estado y la pagina a la aplicación
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## Vamos a analizarlo.
<div align="center">
<img src="https://github.com/reflex-dev/reflex/blob/main/docs/images/dalle_colored_code_example.png?raw=true" alt="Explicando las diferencias entre las partes del backend y frontend de la aplicación DALL-E." width="900" />
</div>
### **Reflex UI**
Empezemos por la interfaz de usuario (UI).
```python
def index():
return rx.center(
...
)
```
Esta función `index` define el frontend de la aplicación.
Utilizamos diferentes componentes como `center`, `vstack`, `input`, y `button` para construir el frontend. Los componentes pueden anidarse unos dentro de otros para crear diseños complejos. Además, puedes usar argumentos de tipo keyword para darles estilo con toda la potencia de CSS.
Reflex viene con [mas de 60 componentes incorporados](https://reflex.dev/docs/library) para ayudarle a empezar. Estamos añadiendo activamente más componentes y es fácil [crear sus propios componentes](https://reflex.dev/docs/wrapping-react/overview/).
### **Estado**
Reflex representa su UI como una función de su estado (State).
```python
class State(rx.State):
"""El estado de la aplicación"""
prompt = ""
image_url = ""
processing = False
complete = False
```
El estado (State) define todas las variables (llamadas vars) de una aplicación que pueden cambiar y las funciones que las modifican.
Aquí el estado se compone de `prompt` e `image_url`. También están los booleanos `processing` y `complete` para indicar cuando se deshabilite el botón (durante la generación de la imagen) y cuando se muestre la imagen resultante.
### **Manejadores de Evento**
```python
def get_image(self):
"""Obtiene la imagen desde la consulta."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Dentro del estado, definimos funciones llamadas manejadores de eventos que cambian las variables de estado. Los Manejadores de Evento son la manera que podemos modificar el estado en Reflex. Pueden ser activados en respuesta a las acciones del usuario, como hacer clic en un botón o escribir en un cuadro de texto. Estas acciones se llaman eventos.
Nuestra aplicación DALL·E tiene un manipulador de eventos, `get_image` que recibe esta imagen del OpenAI API. El uso de `yield` en medio de un manipulador de eventos hará que la UI se actualice. De lo contrario, la interfaz se actualizará al final del manejador de eventos.
### **Enrutamiento**
Por último, definimos nuestra app.
```python
app = rx.App()
```
Añadimos una página desde la raíz (root) de la aplicación al componente de índice (index). También agregamos un título que se mostrará en la vista previa de la página/pestaña del navegador.
```python
app.add_page(index, title="DALL-E")
```
Puedes crear una aplicación multipágina añadiendo más páginas.
## 📑 Recursos
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Librería de componentes](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Galería](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Despliegue](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Estado
Reflex se lanzó en diciembre de 2022 con el nombre de Pynecone.
¡Desde febrero de 2024, nuestro servicio de alojamiento está en fase alfa! Durante este tiempo, cualquiera puede implementar sus aplicaciones de forma gratuita. Consulta nuestra [hoja de ruta](https://github.com/reflex-dev/reflex/issues/2727) para ver qué está planeado.
¡Reflex tiene nuevas versiones y características cada semana! Asegúrate de :star: marcar como favorito y :eyes: seguir este repositorio para mantenerte actualizado.
## Contribuciones
¡Aceptamos contribuciones de cualquier tamaño! A continuación encontrará algunas buenas formas de iniciarse en la comunidad Reflex.
- **Únete a nuestro Discord**: Nuestro [Discord](https://discord.gg/T5WSbC2YtQ) es el mejor lugar para obtener ayuda en su proyecto Reflex y discutir cómo puedes contribuir.
- **Discusiones de GitHub**: Una excelente manera de hablar sobre las características que deseas agregar o las cosas que te resultan confusas o necesitan aclaración.
- **GitHub Issues**: Las incidencias son una forma excelente de informar de errores. Además, puedes intentar resolver un problema existente y enviar un PR.
Buscamos colaboradores, sin importar su nivel o experiencia. Para contribuir consulta [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Licencia
Reflex es de código abierto y está licenciado bajo la [Apache License 2.0](LICENSE).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 KiB

View File

@ -1,252 +0,0 @@
```diff
Pynecone की तलाश हैं? आप सही रेपो में हैं। Pynecone का नाम Reflex में बदल दिया गया है। + +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex लोगो" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex लोगो" width="300px">
<hr>
### **✨ प्रदर्शनकारी, अनुकूलित वेब ऐप्स, शुद्ध Python में। सेकंडों में तैनात करें। ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
## [English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
# Reflex
Reflex शुद्ध पायथन में पूर्ण-स्टैक वेब ऐप्स बनाने के लिए एक लाइब्रेरी है।
मुख्य विशेषताएँ:
- **शुद्ध पायथन** - अपने ऐप के फ्रंटएंड और बैकएंड को पायथन में लिखें, जावास्क्रिप्ट सीखने की जरूरत नहीं है।
- **पूर्ण लचीलापन** - Reflex के साथ शुरुआत करना आसान है, लेकिन यह जटिल ऐप्स के लिए भी स्केल कर सकता है।
- **तुरंत तैनाती** - बिल्डिंग के बाद, अपने ऐप को [एकल कमांड](https://reflex.dev/docs/hosting/deploy-quick-start/) के साथ तैनात करें या इसे अपने सर्वर पर होस्ट करें।
Reflex के अंदर के कामकाज को जानने के लिए हमारे [आर्किटेक्चर पेज](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) को देखें।
## ⚙️ इंस्टॉलेशन (Installation)
एक टर्मिनल खोलें और चलाएं (Python 3.10+ की आवश्यकता है):
```bash
pip install reflex
```
## 🥳 अपना पहला ऐप बनाएं (Create your first App)
reflex को इंस्टॉल करने से ही reflex कमांड लाइन टूल भी इंस्टॉल हो जाता है।
सुनिश्चित करें कि इंस्टॉलेशन सफल थी, एक नया प्रोजेक्ट बनाकर इसे टेस्ट करें। ('my_app_name' की जगह अपने प्रोजेक्ट का नाम रखें):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
यह कमांड आपकी नयी डायरेक्टरी में एक टेम्पलेट ऐप को प्रारंभ करता है।
आप इस ऐप को development मोड में चला सकते हैं:
```bash
reflex run
```
आपको http://localhost:3000 पर अपने ऐप को चलते हुए देखना चाहिए।
अब आप my_app_name/my_app_name.py में source कोड को संशोधित कर सकते हैं। Reflex में तेज रिफ्रेश की सुविधा है, इसलिए जब आप अपनी कोड को सहेजते हैं, तो आप अपने बदलावों को तुरंत देख सकते हैं।
## 🫧 उदाहरण ऐप (Example App)
एक उदाहरण पर चलते हैं: DALL·E से एक इमेज उत्पन्न करने के लिए UI। सरलता के लिए, हम सिर्फ OpenAI API को बुलाते हैं, लेकिन आप इसे ML मॉडल से बदल सकते हैं locally।
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="DALL·E के लिए एक फ्रंटएंड रैपर, छवि उत्पन्न करने की प्रक्रिया में दिखाया गया।" width="550" />
</div>
&nbsp;
यहाँ पर इसका पूरा कोड है जिससे यह बनाया जा सकता है। यह सब एक ही Python फ़ाइल में किया गया है!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## इसे समझते हैं।
<div align="center">
<img src="https://github.com/reflex-dev/reflex/blob/main/docs/images/dalle_colored_code_example.png?raw=true" alt="DALL-E ऐप के बैकएंड और फ्रंटएंड भागों के बीच के अंतर की व्याख्या करता है।" width="900" />
</div>
### **Reflex UI**
हम UI के साथ शुरू करेंगे।
```python
def index():
return rx.center(
...
)
```
यह `index` फ़ंक्शन एप्लिकेशन की फ़्रंटएंड को परिभाषित करता है।
हम फ़्रंटएंड बनाने के लिए `center`, `vstack`, `input`, और `button` जैसे विभिन्न components का उपयोग करते हैं। Components को एक-दूसरे के भीतर डाल सकते हैं विस्तारित लेआउट बनाने के लिए। और आप CSS की पूरी ताक़त के साथ इन्हें स्टाइल करने के लिए कीवर्ड आर्ग्यूमेंट (keyword args) का उपयोग कर सकते हैं।
रिफ़्लेक्स के पास [60+ built-in components](https://reflex.dev/docs/library) हैं जो आपको शुरुआती मदद के लिए हैं। हम बहुत से components जोड़ रहे हैं, और अपने खुद के components बनाना भी आसान है। [create your own components](https://reflex.dev/docs/wrapping-react/overview/)
### **स्टेट (State)**
Reflex आपके UI को आपकी स्टेट (state) के एक फ़ंक्शन के रूप में प्रस्तुत करता है।
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
स्टेट (state) ऐप में उन सभी वेरिएबल्स (vars) को परिभाषित करती है जो बदल सकती हैं और उन फ़ंक्शनों को जो उन्हें बदलते हैं।
यहां स्टेट (state) में `prompt` और `image_url` शामिल हैं। प्रगति और छवि दिखाने के लिए `processing` और `complete` बूलियन भी हैं।
### **इवेंट हैंडलर (Event Handlers)**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
स्टेट (state) के अंदर, हम इवेंट हैंडलर्स (event handlers) को परिभाषित करते हैं जो स्टेट वेरिएबल्स को बदलते हैं। इवेंट हैंडलर्स (event handlers) से reflex में स्टेट (state) को मॉडिफ़ाय किया जा सकता हैं। इन्हें उपयोगकर्ता क्रियाओं (user actions) के प्रति प्रतिक्रिया (response) के रूप में बुलाया जा सकता है, जैसे कि बटन को क्लिक करना या टेक्स्ट बॉक्स में टाइप करना। इन क्रियाओं को इवेंट्स (events) कहा जाता है।
हमारे DALL·E. ऐप में एक इवेंट हैंडलर `get_image` है जिससे यह OpenAI API से इमेज प्राप्त करता है। इवेंट हैंडलर में `yield` का उपयोग करने कि वजह से UI अपडेट हो जाएगा। अन्यथा UI इवेंट हैंडलर के अंत में अपडेट होगा।
### **रूटिंग (Routing)**
आखिरकार, हम अपने एप्लिकेशन को परिभाषित करते हैं।
```python
app = rx.App()
```
हम अपने एप्लिकेशन के रूट से इंडेक्स कॉम्पोनेंट तक एक पेज को जोड़ते हैं। हम एक शीर्षक भी जोड़ते हैं जो पेज प्रीव्यू/ब्राउज़र टैब में दिखाई देगा।
```python
app.add_page(index, title="DALL-E")
```
आप और पेज जोड़कर एक मल्टी-पेज एप्लिकेशन बना सकते हैं।
## 📑 संसाधन (Resources)
<div align="center">
📑 [दस्तावेज़](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [ब्लॉग](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [कॉम्पोनेंट लाइब्रेरी](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [गैलरी](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [तैनाती](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div>
## ✅ स्टेटस (Status)
Reflex दिसंबर 2022 में Pynecone नाम से शुरू हुआ।
फरवरी 2024 तक, हमारी होस्टिंग सेवा अल्फा में है! इस समय कोई भी अपने ऐप्स को मुफ्त में तैनात कर सकता है। देखें हमारी [रोडमैप](https://github.com/reflex-dev/reflex/issues/2727) योजनाबद्ध चीज़ों को जानने के लिए।
Reflex में हर सप्ताह नए रिलीज़ और फीचर्स आ रहे हैं! सुनिश्चित करें कि ⭐ स्टार और 👀 वॉच इस रेपोजिटरी को अपडेट रहने के लिए।
## (योगदान) Contributing
हम हर तरह के योगदान का स्वागत करते हैं! रिफ्लेक्स कम्यूनिटी में शुरुआत करने के कुछ अच्छे तरीके नीचे दिए गए हैं।
- **Join Our Discord** (डिस्कॉर्ड सर्वर से जुड़ें): Our [Discord](https://discord.gg/T5WSbC2YtQ) हमारा डिस्कॉर्ड रिफ्लेक्स प्रोजेक्ट पर सहायता प्राप्त करने और आप कैसे योगदान दे सकते हैं, इस पर चर्चा करने के लिए सबसे अच्छी जगह है।
- **GitHub Discussions** (गिटहब चर्चाएँ): उन सुविधाओं के बारे में बात करने का एक शानदार तरीका जिन्हें आप जोड़ना चाहते हैं या ऐसी चीज़ें जो भ्रमित करने वाली हैं/स्पष्टीकरण की आवश्यकता है।
- **GitHub Issues** (गिटहब समस्याएं): ये [बग](https://github.com/reflex-dev/reflex/issues) की रिपोर्ट करने का एक शानदार तरीका है। इसके अतिरिक्त, आप किसी मौजूदा समस्या को हल करने का प्रयास कर सकते हैं और एक पीआर सबमिट कर सकते हैं।
हम सक्रिय रूप से योगदानकर्ताओं की तलाश कर रहे हैं, चाहे आपका कौशल स्तर या अनुभव कुछ भी हो।योगदान करने के लिए [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) देखें।
## हमारे सभी योगदानकर्ताओं का धन्यवाद:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## लाइसेंस (License)
रिफ्लेक्स ओपन-सोर्स है और [अपाचे लाइसेंस 2.0](https://github.com/reflex-dev/reflex/blob/main/LICENSE) के तहत लाइसेंस प्राप्त है।

View File

@ -1,230 +0,0 @@
```diff
+ Stai cercando Pynecone? Sei nella repository giusto. Pynecone è stato rinominato in Reflex. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ App web performanti e personalizzabili in puro Python. Distribuisci in pochi secondi. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) |
[Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ Installazione
Apri un terminale ed esegui (Richiede Python 3.10+):
```bash
pip install reflex
```
## 🥳 Crea la tua prima app
Installando `reflex` si installa anche lo strumento da riga di comando `reflex`.
Verifica che l'installazione sia stata eseguita correttamente creando un nuovo progetto. (Sostituisci `nome_app` con il nome del tuo progetto):
```bash
mkdir nome_app
cd nome_app
reflex init
```
Questo comando inizializza un'app template nella tua nuova directory.
Puoi eseguire questa app in modalità sviluppo con:
```bash
reflex run
```
Dovresti vedere la tua app in esecuzione su http://localhost:3000.
Ora puoi modificare il codice sorgente in `nome_app/nome_app.py`. Reflex offre aggiornamenti rapidi, così puoi vedere le tue modifiche istantaneamente quando salvi il tuo codice.
## 🫧 Esempio App
Esaminiamo un esempio: creare un'interfaccia utente per la generazione di immagini attorno a DALL·E. Per semplicità, chiamiamo semplicemente l'API OpenAI, ma potresti sostituirla con un modello ML eseguito localmente.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="Un wrapper frontend per DALL·E, mostrato nel processo di generazione di un'immagine." width="550" />
</div>
&nbsp;
Ecco il codice completo per crearlo, Tutto fatto in un unico file Python!
```python
import reflex as rx
import openai
openai.api_key = "TUA_API_KEY"
class State(rx.State):
"""Lo stato dell'app."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Ottieni l'immagine dal prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Vuoto")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Prompt Vuoto", on_blur=State.set_prompt),
rx.button(
"Genera Immagine",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
),
padding="2em",
shadow="lg",
border_radius="lg",
),
width="100%",
height="100vh",
)
# Aggiungi stato e pagina all'app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
```
## Analizziamolo
### **Reflex UI**
Cominciamo con l'UI.
```python
def index():
return rx.center(
...
)
```
Questo `index` definisce il frontend dell'app.
Utilizziamo diversi componenti come `center`, `vstack`, `input`, e `button` per costruire il frontend. I componenti possono essere annidati gli uni negli altri per creare layout complessi. Puoi utilizzare argomenti chiave per stilizzarli con tutta la potenza di CSS.
Reflex offre [più di 60 componenti integrati](https://reflex.dev/docs/library) per aiutarti a iniziare. Stiamo attivamente aggiungendo più componenti ed è facile [creare i tuoi componenti](https://reflex.dev/docs/wrapping-react/overview/).
### **Stato (State)**
Reflex rappresenta la tua UI come una funzione del tuo stato.
```python
class State(rx.State):
"""Lo stato dell'app."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Lo stato definisce tutte le variabili (chiamate vars) in un'app che possono cambiare e le funzioni che le cambiano.
Qui lo stato è composto da un `prompt` e `image_url`. Ci sono anche i booleani `processing` e `complete` per indicare quando mostrare l'andamento circolare e l'immagine.
### **Gestori di Eventi (Event Handlers)**
```python
def get_image(self):
"""Ottieni l'immagine dal prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Vuoto")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
self.processing, self.complete = False, True
```
Dentro lo stato, definiamo funzioni chiamate gestori di eventi che cambiano le vars dello stato. I gestori di eventi sono il modo in cui possiamo modificare lo stato in Reflex. Possono essere chiamati in risposta alle azioni dell'utente, come fare clic su un pulsante o digitare in una casella di testo. Queste azioni vengono chiamate eventi.
La nostra app DALL·E ha un gestore di eventi, `get_image` con cui ottiene questa immagine dall'API OpenAI. Utilizzando `yield` nel mezzo di un gestore di eventi farà sì che l'UI venga aggiornata. Altrimenti, l'UI verrà aggiornata alla fine del gestore di eventi.
### **Instradamento (Routing)**
Infine, definiamo la nostra app.
```python
app = rx.App()
```
Possiamo aggiungere una pagina dalla radice dell'app al componente dell'indice.Aggiungiamo anche un titolo che apparirà nell'anteprima della pagina/scheda del browser
```python
app.add_page(index, title="DALL-E")
```
Puoi creare un'app multi-pagina aggiungendo altre pagine.
## 📑 Risorse
<div align="center">
📑 [Documentazione](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Libreria Componenti](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Immagini](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Distribuzione](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div>
## ✅ Stato
Reflex è stato lanciato nel dicembre 2022 con il nome Pynecone.
Da luglio 2023, siamo nella fase di Beta Pubblica.
- :white_check_mark: **Alfa Pubblica**: Chiunque può installare e utilizzare Reflex. Potrebbero esserci dei problemi, ma stiamo lavorando per risolverli attivamente.
- :large_orange_diamond: **Beta Pubblica**: Abbastanza stabile per casi d'uso non aziendali.
- **Beta Hosting Pubblico**: _Opzionalmente_, distribuisci e ospita le tue app su Reflex!
- **Pubblico**: Reflex è pronto per la produzione.
Reflex ha nuove versioni e funzionalità in arrivo ogni settimana! Assicurati di :star: mettere una stella e :eyes: osservare questa repository per rimanere aggiornato.
## Contribuire
Diamo il benvenuto a contributi di qualsiasi dimensione! Di seguito sono alcuni modi per iniziare nella comunità Reflex.
- **Unisciti al nostro Discord**: Il nostro [Discord](https://discord.gg/T5WSbC2YtQ) è posto migliore per ottenere aiuto sul tuo progetto Reflex e per discutere come puoi contribuire.
- **Discussioni su GitHub**: Un ottimo modo per parlare delle funzionalità che desideri aggiungere o di cose che creano confusione o necessitano chiarimenti.
- **GitHub Issues**: Sono un ottimo modo per segnalare bug. Inoltre, puoi provare a risolvere un problema esistente e inviare un PR.
Stiamo attivamente cercando collaboratori, indipendentemente dal tuo livello di abilità o esperienza.
## Licenza
Reflex è open-source e rilasciato sotto la [Licenza Apache 2.0](LICENSE).

View File

@ -1,255 +0,0 @@
```diff
+ PyneconeはReflexに名前を変えました。Pyneconeを探している方は、今、ご覧のページがPyneconeのリポジトリになります。 +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ 即時デプロイが可能な、Pure Python で作ったパフォーマンスと汎用性が高い Web アプリケーション ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex
Reflex は Python のみでフルスタック Web アプリケーションを作成できるライブラリです。
主な特徴:
- **Pure Python** - Web アプリケーションのフロントエンドとバックエンドを Python のみで実装できるため、Javascript を学ぶ必要がありません。
- **高い柔軟性** - Reflex は簡単に始められて、複雑なアプリケーションまで作成できます。
- **即時デプロイ** - ビルド後、すぐにデプロイが可能です。[単純な CLI コマンド](https://reflex.dev/docs/hosting/deploy-quick-start/)を使ったアプリケーションのデプロイや、自身のサーバーへのホストができます。
Reflex がどのように動作しているかを知るには、[アーキテクチャページ](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)をご覧ください。
## ⚙️ インストール
ターミナルを開いて以下のコマンドを実行してください。Python 3.10 以上が必要です。):
```bash
pip install reflex
```
## 🥳 最初のアプリケーションを作ろう
`reflex`をインストールすると、`reflex`の CLI ツールが自動でインストールされます。
新しいプロジェクトを作成して、インストールが成功しているかを確認しましょう。(`my_app_name`を自身のプロジェクト名に書き換えて実行ください。):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
上記のコマンドを実行すると、新しいフォルダにテンプレートアプリを作成します。
下記のコマンドを実行すると、開発モードでアプリを開始します。
```bash
reflex run
```
http://localhost:3000 にアクセスしてアプリの動作を見ることができます。
`my_app_name/my_app_name.py`のソースコードを編集してみましょうReflex は fast refresh なので、ソースを保存した直後に変更が Web ページに反映されます。
## 🫧 実装例
実装例を見てみましょう: [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node)を中心とした画像生成 UI を作成しました。説明を簡単にするためにここでは[OpenAI API](https://platform.openai.com/docs/api-reference/authentication)を呼んでいますが、ローカルで動作している機械学習モデルに置き換えることも可能です。
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="DALL·Eのフロントエンドラッパーです。画像を生成している過程を表示しています。" width="550" />
</div>
&nbsp;
画像生成 UI のソースコードの全貌を見てみましょう。下記のように、単一の Python ファイルで作れます!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""アプリのステート"""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""プロンプトからイメージを取得する"""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# ステートとページをアプリに追加
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## それぞれの実装を見てみましょう
<div align="center">
<img src="../../docs/images/dalle_colored_code_example.png" alt="DALL-E appのフロントエンドとバックエンドのパーツの違いを説明しています。" width="900" />
</div>
### **Reflex UI**
UI から見てみましょう。
```python
def index():
return rx.center(
...
)
```
`index`関数において、アプリのフロントエンドを定義しています。
フロントエンドを実装するにあたり、`center`、`vstack`、`input`、`button`など異なるコンポーネントを使用しています。コンポーネントはお互いにネストが可能であり、複雑なレイアウトを作成できます。また、keyword args を使うことで、CSS の機能をすべて使ったスタイルが可能です。
Reflex は[60 を超える内臓コンポーネント](https://reflex.dev/docs/library)があるため、すぐに始められます。私たちは、積極的にコンポーネントを追加していますが、簡単に[自身のコンポーネントを追加](https://reflex.dev/docs/wrapping-react/overview/)することも可能です。
### **ステート**
Reflex はステートの関数を用いて UI を表示します。
```python
class State(rx.State):
"""アプリのステート"""
prompt = ""
image_url = ""
processing = False
complete = False
```
ステートでは、アプリで変更が可能な全ての変数vars と呼びますと、vars の変更が可能な関数を定義します。
この例では、ステートを`prompt`と`image_url`で構成しています。そして、ブール型の`processing`と`complete`を用いて、ボタンを無効にするタイミング(画像生成中)や生成された画像を表示するタイミングを示しています。
### **イベントハンドラ**
```python
def get_image(self):
"""プロンプトからイメージを取得する"""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
ステートにおいて、ステートの vars を変更できるイベントハンドラ関数を定義しています。イベントハンドラは Reflex において、ステートの vars を変更する方法です。ボタンクリックやテキストボックスの入力など、ユーザのアクションに応じてイベントハンドラが呼ばれます。
DALL·E.アプリには、OpenAI API からイメージを取得する`get_image`関数があります。イベントハンドラの最後で UI の更新がかかるため、関数の途中に`yield`を入れることで先に UI を更新しています。
### **ルーティング**
最後に、アプリを定義します。
```python
app = rx.App()
```
アプリにページを追加し、ドキュメントルートを index コンポーネントにルーティングしています。更に、ページのプレビューやブラウザタブに表示されるタイトルを記載しています。
```python
app.add_page(index, title="DALL-E")
```
ページを追加することで、マルチページアプリケーションを作成できます。
## 📑 リソース
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ ステータス
2022 年 12 月に、Reflex は Pynecone という名前でローンチしました。
2024 年 2 月に、ホスティングサービスをアルファ版でリリースしました!アルファ版では、だれでも Reflex アプリケーションを無料でデプロイできます。今後の予定は[ロードマップ](https://github.com/reflex-dev/reflex/issues/2727)において見れます。
Reflex は毎週、新しいリリースや機能追加を行っています!最新情報を逃さないために、 :star: Star や :eyes: Watch をお願いします。
## コントリビュート
様々なサイズのコントリビュートを歓迎していますReflex コミュニティに入るための方法を、いくつかリストアップします。
- **Discord に参加**: [Discord](https://discord.gg/T5WSbC2YtQ)は、Reflex プロジェクトの相談や、コントリビュートについての話し合いをするための、最適な場所です。
- **GitHub Discussions**: GitHub Discussions では、追加したい機能や、複雑で解明が必要な事柄についての議論に適している場所です。
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues)はバグの報告に適している場所です。また、課題を解決した PR のサブミットにチャレンジしていただくことも、可能です。
CONTスキルや経験に関わらず、私たちはコントリビュータを積極的に探しています。コントリビュートするために、[CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)をご覧ください。
## 私たちのコントリビュータに感謝!:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## ライセンス
Reflex はオープンソースであり、[Apache License 2.0](LICENSE)に基づいてライセンス供与されます。

View File

@ -1,240 +0,0 @@
```diff
+ Pynecone을 찾고 계신가요? 이곳이 맞습니다. Pynecone은 이제 Reflex로 불립니다. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ 순수 Python으로 고성능 사용자 정의 웹앱을 만들어 보세요. 몇 초만에 배포 가능합니다. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ 설치
터미널을 열고 실행하세요. (Python 3.10+ 필요):
```bash
pip install reflex
```
## 🥳 첫 앱 만들기
`reflex`를 설치하면, `reflex` 명령어 라인 도구도 설치됩니다.
새 프로젝트를 생성하여 설치가 성공적인지 확인합니다. (`my_app_name`을 프로젝트 이름으로 변경합니다.):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
이 명령어는 새 디렉토리에 템플릿 앱을 초기화합니다.
개발 모드에서 이 앱을 실행할 수 있습니다:
```bash
reflex run
```
http://localhost:3000 에서 앱이 실행 됩니다.
이제 `my_app_name/my_app_name.py`에서 소스코드를 수정할 수 있습니다. Reflex는 빠른 새로고침을 지원하므로 코드를 저장할 때마다 즉시 변경 사항을 볼 수 있습니다.
## 🫧 예시 앱
예시를 살펴보겠습니다: DALL·E를 중심으로 이미지 생성 UI를 만들어 보겠습니다. 간단하게 하기 위해 OpenAI API를 호출했지만, 이를 로컬에서 실행되는 ML 모델로 대체할 수 있습니다.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
이것이 완성된 코드입니다. 이 모든 것은 하나의 Python 파일에서 이루어집니다!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## 하나씩 살펴보겠습니다.
### **Reflex UI**
UI부터 시작해봅시다.
```python
def index():
return rx.center(
...
)
```
`index` 함수는 앱의 프론트엔드를 정의합니다.
`center`, `vstack`, `input`, `button`과 같은 다양한 컴포넌트를 사용하여 프론트엔드를 구축합니다.
컴포넌트들은 복잡한 레이아웃을 만들기 위해 서로 중첩될 수 있습니다.
그리고 키워드 인자를 사용하여 CSS의 모든 기능을 사용하여 스타일을 지정할 수 있습니다.
Reflex는 시작하기 위한 [60개 이상의 기본 컴포넌트](https://reflex.dev/docs/library)를 제공하고 있습니다. 더 많은 컴포넌트를 추가하고 있으며, [자신만의 컴포넌트를 생성하는 것](https://reflex.dev/docs/wrapping-react/overview/)도 쉽습니다.
### **State**
Reflex는 UI를 State 함수로 표현합니다.
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
state는 앱에서 변경될 수 있는 모든 변수(vars로 불림)와 이러한 변수를 변경하는 함수를 정의합니다.
여기서 state는 `prompt``image_url`로 구성됩니다. 또한 `processing``complete`라는 불리언 값이 있습니다. 이 값들은 이미지 생성 중 버튼을 비활성화할 때와, 결과 이미지를 표시할 때를 나타냅니다.
### **Event Handlers**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
State 내에서, state vars를 변경하는 이벤트 핸들러라고 불리는 함수를 정의합니다. 이벤트 핸들러는 Reflex에서 state를 변경하는 방법입니다. 버튼을 클릭하거나 텍스트 상자에 입력하는 것과 같이 사용자 동작에 응답하여 호출될 수 있습니다. 이러한 동작을 이벤트라고 합니다.
DALL·E. 앱에는 OpenAI API에서 이미지를 가져오는 `get_image` 이벤트 핸들러가 있습니다. 이벤트 핸들러의 중간에 `yield`를 사용하면 UI가 업데이트됩니다. 그렇지 않으면 UI는 이벤트 핸들러의 끝에서 업데이트됩니다.
### **Routing**
마지막으로, 앱을 정의합니다.
```python
app = rx.App()
```
앱의 루트에서 index 컴포넌트로 페이지를 추가합니다. 또한 페이지 미리보기/브라우저 탭에 표시될 제목도 추가합니다.
```python
app.add_page(index, title="DALL-E")
```
여러 페이지를 추가하여 멀티 페이지 앱을 만들 수 있습니다.
## 📑 자료
<div align="center">
📑 [문서](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [블로그](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [컴포넌트 라이브러리](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [갤러리](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [배포](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div>
## ✅ 상태
Reflex는 2022년 12월 Pynecone이라는 이름으로 출시되었습니다.
2023년 7월 현재, 우리는 **Public Beta** 상태에 있습니다.
- :white_check_mark: **Public Alpha**: 누구나 Reflex를 설치하고 사용할 수 있습니다. 문제가 발생할 수도 있지만 적극적으로 수정합니다.
- :large_orange_diamond: **Public Beta**: 비상업적 용도로 충분히 안정적입니다.
- **Public Hosting Beta**: _선택적으로_, Reflex에서 앱을 배포하고 호스팅할 수 있습니다!
- **Public** : Reflex는 프로덕션 준비를 마쳤습니다.
Reflex는 매주 새로운 릴리즈와 기능을 제공합니다! 최신 정보를 확인하려면 :star: Star와 :eyes: Watch를 눌러 이 저장소를 확인하세요.
## 기여
우리는 모든 기여를 환영합니다! 아래는 Reflex 커뮤니티에 참여하는 좋은 방법입니다.
- **Discord 참여**: 우리의 [Discord](https://discord.gg/T5WSbC2YtQ)는 Reflex 프로젝트에 대한 도움을 받고 기여하는 방법을 논의하는 최고의 장소입니다.
- **GitHub Discussions**: 추가하고 싶은 기능이나 혼란스럽거나 해결이 필요한 것들에 대해 이야기하는 좋은 방법입니다.
- **GitHub Issues**: 이것은 버그를 보고하는 훌륭한 방법입니다. 또한, 기존의 이슈를 해결하고 PR을 제출할 수 있습니다.
우리는 능력이나 경험에 상관없이 적극적으로 기여자를 찾고 있습니다.
## License
Reflex는 오픈소스이며 [Apache License 2.0](LICENSE)로 라이선스가 부여됩니다.

View File

@ -1,262 +0,0 @@
```diff
+ دنبال Pynecone میگردی؟ شما در مخزن درستی قرار داری. Pynecone به Reflex تغییر نام داده است. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ برنامه های تحت وب قابل تنظیم، کارآمد تماما پایتونی که در چند ثانیه مستقر(دپلوی) می‎شود. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
# Reflex - رفلکس
رفلکس(Reflex) یک کتابخانه برای ساخت برنامه های وب فول استک تماما پایتونی است.
ویژگی های کلیدی:
* **تماما پایتونی** - فرانت اند و بک اند برنامه خود را همه در پایتون بنویسید، بدون نیاز به یادگیری جاوا اسکریپت.
* **انعطاف پذیری کامل** - شروع به کار با Reflex آسان است، اما می تواند به برنامه های پیچیده نیز تبدیل شود.
* **دپلوی فوری** - پس از ساخت، برنامه خود را با [یک دستور](https://reflex.dev/docs/hosting/deploy-quick-start/) دپلوی کنید یا آن را روی سرور خود میزبانی کنید.
برای آشنایی با نحوه عملکرد Reflex [صفحه معماری](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) را ببینید.
## ⚙️ Installation - نصب و راه اندازی
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.10+):
```bash
pip install reflex
```
## 🥳 اولین برنامه خود را ایجاد کنید
نصب `reflex` همچنین `reflex` در خط فرمان را نصب میکند.
با ایجاد یک پروژه جدید موفقیت آمیز بودن نصب را تست کنید. (`my_app_name` را با اسم پروژه خودتان جایگزین کنید):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
این دستور یک برنامه الگو(تمپلیت) را در فهرست(دایرکتوری) جدید شما مقداردهی اولیه می کند
می توانید این برنامه را در حالت توسعه(development) اجرا کنید:
```bash
reflex run
```
باید برنامه خود را در حال اجرا ببینید در http://localhost:3000.
اکنون می‌توانید کد منبع را در «my_app_name/my_app_name.py» تغییر دهید. Reflex دارای تازه‌سازی‌های سریعی است، بنابراین می‌توانید تغییرات خود را بلافاصله پس از ذخیره کد خود مشاهده کنید.
## 🫧 Example App - برنامه نمونه
بیایید یک مثال بزنیم: ایجاد یک رابط کاربری برای تولید تصویر [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). برای سادگی، ما فراخوانی میکنیم [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), اما می توانید آن را با یک مدل ML که به صورت محلی اجرا می شود جایگزین کنید.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
در اینجا کد کامل برای ایجاد این پروژه آمده است. همه اینها در یک فایل پایتون انجام می شود!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## بیاید سادش کنیم
<div align="center">
<img src="docs/images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
</div>
### **Reflex UI - رابط کاربری رفلکس**
بیایید با رابط کاربری شروع کنیم.
```python
def index():
return rx.center(
...
)
```
تابع `index` قسمت فرانت اند برنامه را تعریف می کند.
ما از اجزای مختلفی مثل `center`, `vstack`, `input` و `button` استفاده میکنیم تا فرانت اند را بسازیم. اجزاء را می توان درون یکدیگر قرار داد
برای ایجاد طرح بندی های پیچیده می توانید از args کلمات کلیدی برای استایل دادن به آنها از CSS استفاده کنید.
رفلکس دارای [بیش از 60 جزء](https://reflex.dev/docs/library) برای کمک به شما برای شروع. ما به طور فعال اجزای بیشتری را اضافه می کنیم, و این خیلی آسان است که [اجزا خود را بسازید](https://reflex.dev/docs/wrapping-react/overview/).
### **State - حالت**
رفلکس رابط کاربری شما را به عنوان تابعی از وضعیت شما نشان می دهد.
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
حالت تمام متغیرها(variables) (به نام vars) را در یک برنامه که می توانند تغییر دهند و توابعی که آنها را تغییر می دهند تعریف می کند..
در اینجا حالت از یک `prompt` و `image_url` تشکیل شده است. همچنین دو بولی `processing` و `complete` برای نشان دادن زمان غیرفعال کردن دکمه (در طول تولید تصویر) و زمان نمایش تصویر نتیجه وجود دارد.
### **Event Handlers - کنترل کنندگان رویداد**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
در داخل حالت، توابعی به نام کنترل کننده رویداد تعریف می کنیم که متغیرهای حالت را تغییر می دهند. کنترل کننده های رویداد راهی هستند که می توانیم وضعیت را در Reflex تغییر دهیم. آنها را می توان در پاسخ به اقدامات کاربر، مانند کلیک کردن روی یک دکمه یا تایپ کردن در یک متن، فراخوانی کرد. به این اعمال وقایع می گویند.
برنامه DALL·E ما دارای یک کنترل کننده رویداد، `get_image` است که این تصویر را از OpenAI API دریافت می کند. استفاده از `yield` در وسط کنترل‌کننده رویداد باعث به‌روزرسانی رابط کاربری می‌شود. در غیر این صورت رابط کاربری در پایان کنترل کننده رویداد به روز می شود.
### **Routing - مسیریابی**
بالاخره اپلیکیشن خود را تعریف می کنیم.
```python
app = rx.App()
```
ما یک صفحه از root برنامه را به جزء index اضافه می کنیم. ما همچنین عنوانی را اضافه می کنیم که در برگه پیش نمایش/مرورگر صفحه نمایش داده می شود.
```python
app.add_page(index, title="DALL-E")
```
با افزودن صفحات بیشتر می توانید یک برنامه چند صفحه ای ایجاد کنید.
## 📑 Resources - منابع
<div align="center">
📑 [اسناد](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [وبلاگ](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [کتابخانه جزء](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [گالری](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [استقرار](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Status - وضعیت
رفلکس(reflex) در دسامبر 2022 با نام Pynecone راه اندازی شد.
از فوریه 2024، سرویس میزبانی ما در آلفا است! در این مدت هر کسی می‌تواند برنامه‌های خود را به صورت رایگان اجرا کند. [نقشه راه](https://github.com/reflex-dev/reflex/issues/2727) را ببینید تا متوجه شوید چه برنامه‌ریزی شده است.
رفلکس(reflex) هر هفته نسخه ها و ویژگی های جدیدی دارد! مطمئن شوید که :star: ستاره و :eyes: این مخزن را تماشا کنید تا به روز بمانید.
## Contributing - مشارکت کردن
ما از مشارکت در هر اندازه استقبال می کنیم! در زیر چند راه خوب برای شروع در انجمن رفلکس آورده شده است.
- **به Discord ما بپیوندید**: [Discord](https://discord.gg/T5WSbC2YtQ) ما بهترین مکان برای دریافت کمک در مورد پروژه Reflex و بحث در مورد اینکه چگونه می توانید کمک کنید است.
- **بحث های GitHub**: راهی عالی برای صحبت در مورد ویژگی هایی که می خواهید اضافه کنید یا چیزهایی که گیج کننده هستند/نیاز به توضیح دارند.
- **قسمت مشکلات GitHub**: [قسمت مشکلات](https://github.com/reflex-dev/reflex/issues) یک راه عالی برای گزارش اشکال هستند. علاوه بر این، می توانید یک مشکل موجود را حل کنید و یک PR(pull request) ارسال کنید.
ما فعالانه به دنبال مشارکت کنندگان هستیم، فارغ از سطح مهارت یا تجربه شما. برای مشارکت [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) را بررسی کنید.
## All Thanks To Our Contributors - با تشکر از همکاران ما:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## License - مجوز
رفلکس متن باز و تحت مجوز [Apache License 2.0](LICENSE) است.

View File

@ -1,235 +0,0 @@
```diff
+ Está procurando pelo Pynecone? Este é o repositório certo. Pynecone foi renomeado para Reflex. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Web apps customizáveis, performáticos, em Python puro. Faça deploy em segundos. ✨**
[![Versão PyPI](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![testes](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versões](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentação](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ Instalação
Abra um terminal e execute (Requer Python 3.10+):
```bash
pip install reflex
```
## 🥳 Crie o seu primeiro app
Instalar `reflex` também instala a ferramenta de linha de comando `reflex`.
Crie um novo projeto para verificar se a instalação foi bem sucedida. (Mude `nome_do_meu_app` com o nome do seu projeto):
```bash
mkdir nome_do_meu_app
cd nome_do_meu_app
reflex init
```
Este comando inicializa um app base no seu novo diretório.
Você pode executar este app em modo desenvolvimento:
```bash
reflex run
```
Você deve conseguir verificar seu app sendo executado em http://localhost:3000.
Agora, você pode modificar o código fonte em `nome_do_meu_app/nome_do_meu_app.py`. O Reflex apresenta recarregamento rápido para que você possa ver suas mudanças instantâneamente quando você salva o seu código.
## 🫧 Exemplo de App
Veja o seguinte exemplo: criar uma interface de criação de imagens por meio do DALL-E. Para fins de simplicidade, vamos apenas chamar a API da OpenAI, mas você pode substituir esta solução por qualquer modelo de aprendizado de máquina que preferir, executando localmente.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="Um encapsulador frontend para o DALL-E, mostrado no processo de criação de uma imagem." width="550" />
</div>
&nbsp;
Aqui está o código completo para criar este projeto. Isso tudo foi feito apenas em um arquivo Python!
```python
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
class State(rx.State):
"""Estado da aplicação."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Obtenção da imagem a partir do prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.button(
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
),
padding="2em",
shadow="lg",
border_radius="lg",
),
width="100%",
height="100vh",
)
# Adição do estado e da página no app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
```
## Vamos por partes.
### **Reflex UI**
Vamos começar com a UI (Interface de Usuário)
```python
def index():
return rx.center(
...
)
```
Esta função `index` define o frontend do app.
Usamos diferentes componentes, como `center`, `vstack`, `input` e `button`, para construir o frontend. Componentes podem ser aninhados um no do outro
para criar layouts mais complexos. E você pode usar argumentos de chave-valor para estilizá-los com todo o poder do CSS.
O Reflex vem com [60+ componentes nativos](https://reflex.dev/docs/library) para te ajudar. Estamos adicionando ativamente mais componentes, mas também é fácil [criar seus próprios componentes](https://reflex.dev/docs/wrapping-react/overview/).
### **Estado**
O Reflex representa a sua UI como uma função do seu estado.
```python
class State(rx.State):
"""Estado da aplicação."""
prompt = ""
image_url = ""
processing = False
complete = False
```
O estado define todas as variáveis (chamadas de vars) que podem ser modificadas por funções no seu app.
Aqui, o estado é composto por um `prompt` e uma `image_url`, representando, respectivamente, o texto que descreve a imagem a ser gerada e a url da imagem gerada.
### **Handlers de Eventos**
```python
def get_image(self):
"""Obtenção da imagem a partir do prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
self.processing, self.complete = False, True
```
Dentro do estado, são definidas funções chamadas de Handlers de Eventos, que podem mudar as variáveis do estado. Handlers de Eventos são a forma com a qual podemos modificar o estado dentro do Reflex. Eles podem ser chamados como resposta a uma ação do usuário, como o clique de um botão ou a escrita em uma caixa de texto. Estas ações geram eventos que são processados pelos Handlers.
Nosso app DALL-E possui um Handler de Evento chamado `get_image`, que obtêm a imagem da API da OpenAI. Usar `yield` no meio de um Handler de Evento causa a atualização da UI do seu app. Caso contrário, a UI seria atualizada no fim da execução de um Handler de Evento.
### **Rotas**
Finalmente, definimos nosso app.
```python
app = rx.App()
```
Adicionamos uma página na raíz do app, apontando para o componente index. Também adicionamos um título ("DALL-E") que irá aparecer na aba no navegador.
```python
app.add_page(index, title="DALL-E")
```
Você pode criar mais páginas e adicioná-las ao seu app.
## 📑 Recursos
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Biblioteca de Componentes](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Galeria](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div>
## ✅ Status
O Reflex foi lançado em Dezembro de 2022 com o nome Pynecone.
Em Julho de 2023, estamos no estágio de **Beta Público**.
- :white_check_mark: **Alpha Público**: Qualquer um pode instalar e usar o Reflex. Podem existir alguns problemas, mas estamos trabalhando ativamente para resolvê-los.
- :large_orange_diamond: **Beta Público**: Estável o suficiente para utilizar em projetos pessoais, com menor criticidade.
- **Hospedagem Pública Beta**: _Opcionalmente_, implante e hospede os seus apps no Reflex!
- **Público**: O Reflex está pronto para produção.
O Reflex agora possui novas versões e funcionalidades sendo lançadas toda semana! Lembre-se de marcar o repositório com uma :star: estrela e :eyes: acompanhe para ficar atualizado sobre o projeto.
## Contribuições
Nós somos abertos a contribuições de qualquer tamanho! Abaixo, seguem algumas boas formas de começar a contribuir para a comunidade do Reflex.
- **Entre no nosso Discord**: Nosso [Discord](https://discord.gg/T5WSbC2YtQ) é o melhor lugar para conseguir ajuda no seu projeto Reflex e para discutir como você pode contribuir.
- **Discussões no GitHub**: Uma boa forma de conversar sobre funcionalidades que você gostaria de ver ou coisas que ainda estão confusas/exigem ajuda.
- **Issues no GitHub**: Excelente forma de reportar bugs. Além disso, você pode tentar resolver alguma issue existente e enviar um Pull Request.
Estamos ativamente buscando novos contribuidores, não importa o seu nível de habilidade ou experiência.
## Licença
O Reflex é um software de código aberto, sob a [Apache License 2.0](LICENSE).

View File

@ -1,242 +0,0 @@
```diff
+ Pynecone'u mu arıyorsun? Doğru repodasın. Pynecone, Reflex olarak yeniden adlandırıldı. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Saf Python'da performanslı, özelleştirilebilir web uygulamaları. Saniyeler içinde dağıtın. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
---
## ⚙️ Kurulum
Bir terminal açın ve çalıştırın (Python 3.10+ gerekir):
```bash
pip install reflex
```
## 🥳 İlk Uygulamanı Oluştur
`reflex`'i kurduğunuzda `reflex` komut satırı aracınıda kurmuş olursunuz.
Kurulumun başarılı olduğunu test etmek için yeni bir proje oluşturun. (`my_app_name`'i proje ismiyle değiştirin.):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Bu komut ile birlikte yeni oluşturduğunuz dizinde bir şablon uygulaması oluşturur.
Uygulamanızı geliştirme modunda başlatabilirsiniz:
```bash
reflex run
```
Uygulamanızın http://localhost:3000 adresinde çalıştığını görmelisiniz.
Şimdi `my_app_name/my_app_name.py` yolundaki kaynak kodu düzenleyebilirsiniz. Reflex'in hızlı yenileme özelliği vardır, böylece kodunuzu kaydettiğinizde değişikliklerinizi anında görebilirsiniz.
## 🫧 Örnek Uygulama
Bir örnek üzerinden gidelim: [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node) kullanarak bir görüntü oluşturma uygulaması yazalım. Basit olmasıısından, yalnızca [OpenAI API](https://platform.openai.com/docs/api-reference/authentication)'ını kullanıyoruz, ancak bunu yerel olarak çalıştırılan bir makine öğrenimi modeliyle değiştirebilirsiniz.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
İşte bunu oluşturmak için kodun tamamaı. Her şey sadece bir Python dosyasıyla hazırlandı!
```python
import reflex as rx
import openai
openai.api_key = "YOUR_API_KEY"
class State(rx.State):
"""Uygulama durumu."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Prompt'tan görüntüyü alın."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL·E"),
rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
rx.button(
"Generate Image",
on_click=State.get_image,
is_loading=State.processing,
width="100%",
),
rx.cond(
State.complete,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
),
padding="2em",
shadow="lg",
border_radius="lg",
),
width="100%",
height="100vh",
)
# Sayfa ve durumu uygulamaya ekleyin.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
```
## Daha Detaylı İceleyelim
### **Reflex UI**
UI (Kullanıcı Arayüzü) ile başlayalım.
```python
def index():
return rx.center(
...
)
```
Bu `index` fonkisyonu uygulamanın frontend'ini tanımlar.
Frontend'i oluşturmak için `center`, `vstack`, `input`, ve `button` gibi farklı bileşenler kullanıyoruz. Karmaşık düzenler oluşturmak için bileşenleri birbirinin içine yerleştirilebiliriz. Ayrıca bunları CSS'nin tüm gücüyle şekillendirmek için anahtar kelime argümanları kullanabilirsiniz.
Reflex, işinizi kolaylaştırmak için [60'tan fazla dahili bileşen](https://reflex.dev/docs/library) içerir. Aktif olarak yeni bileşen ekliyoruz ve [kendi bileşenlerinizi oluşturmak](https://reflex.dev/docs/wrapping-react/overview/) oldukça kolay.
### **Durum (State)**
Reflex arayüzünüzü durumunuzun bir fonksiyonu olarak temsil eder.
```python
class State(rx.State):
"""Uygulama durumu."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Durum (State), bir uygulamadaki değişebilen tüm değişkenleri (vars olarak adlandırılır) ve bunları değiştiren fonksiyonları tanımlar.
Burada durum `prompt` ve `image_url`inden oluşur. Ayrıca döngüsel ilerlemenin ve görüntünün ne zaman gösterileceğini belirtmek için `processing` ve `complete` booleanları da vardır.
### **Olay İşleyicileri (Event Handlers)**
```python
def get_image(self):
"""Prompt'tan görüntüyü alın."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
self.image_url = response["data"][0]["url"]
self.processing, self.complete = False, True
```
Durum içinde, durum değişkenlerini değiştiren olay işleyicileri adı verilen fonksiyonları tanımlarız. Olay işleyicileri, Reflex'te durumu değiştirebilmemizi sağlar. Bir düğmeye tıklamak veya bir metin kutusuna yazı yazmak gibi kullanıcı eylemlerine yanıt olarak çağrılabilirler. Bu eylemlere olay denir.
DALL·E uygulamamız bir olay işleyicisine sahip, `get_image` ki bu da OpenAI API'ından oluşturulan resmi alır. Bir olay işleyicisinin ortasında `yield`ın kullanılması UI'ın güncellenmesini sağlar. Aksi takdirde UI olay işleyicisinin sonunda güncellenecektir.
### **Yönlendirme (Routing)**
En sonunda uygulamamızı tanımlıyoruz.
```python
app = rx.App()
```
Uygulamamızın kök dizinine index bileşeninden bir sayfa ekliyoruz. Ayrıca sayfa önizlemesinde/tarayıcı sekmesinde görünecek bir başlık ekliyoruz.
```python
app.add_page(index, title="DALL-E")
```
Daha fazla sayfa ekleyerek çok sayfalı bir uygulama oluşturabilirsiniz.
## 📑 Kaynaklar
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div>
## ✅ Durum
Reflex, Aralık 2022'de Pynecone adıyla piyasaya sürüldü.
Temmuz 2023 itibarıyla **Herkese Açık Beta** aşamasındayız.
- :white_check_mark: **Public Alpha**: Herkes Reflex'i yükleyebilir ve kullanabilir. Sorunlar olabilir, ancak bunları aktif olarak çözmek için çalışıyoruz.
- :large_orange_diamond: **Public Beta**: Kurumsal olmayan kullanım durumları için yeterince kararlı.
- **Public Hosting Beta**: _Optionally_, uygulamalarınızı Reflex ile dağıtın ve barındırın!
- **Public**: Reflex kullanıma hazır.
Reflex'in her hafta yeni sürümleri ve özellikleri geliyor! Güncel kalmak için :star: yıldızlamayı ve bu repoyu :eyes: izlediğinizden emin olun.
## Katkı
Her boyuttaki katkıları memnuniyetle karşılıyoruz! Aşağıda Reflex topluluğuna adım atmanın bazı yolları mevcut.
- **Discord Kanalımıza Katılın**: [Discord'umuz](https://discord.gg/T5WSbC2YtQ), Reflex projeniz hakkında yardım almak ve nasıl katkıda bulunabileceğinizi tartışmak için en iyi yerdir.
- **GitHub Discussions**: Eklemek istediğiniz özellikler veya kafa karıştırıcı, açıklığa kavuşturulması gereken şeyler hakkında konuşmanın harika bir yolu.
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) hataları bildirmenin mükemmel bir yoludur. Ayrıca mevcut bir sorunu deneyip çözebilir ve bir PR (Pull Requests) gönderebilirsiniz.
Beceri düzeyiniz veya deneyiminiz ne olursa olsun aktif olarak katkıda bulunacak kişiler arıyoruz. Katkı sağlamak için katkı sağlama rehberimize bakabilirsiniz: [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Hepsi Katkıda Bulunanlar Sayesinde:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## Lisans
Reflex açık kaynaklıdır ve [Apache License 2.0](LICENSE) altında lisanslıdır.

View File

@ -1,267 +0,0 @@
```diff
+ Bạn đang tìm kiếm Pynecone? Bạn đã tìm đúng. Pynecone đã được đổi tên thành Reflex. +
```
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<hr>
### **✨ Ứng dụng web hiệu suất cao, tùy chỉnh bằng Python thuần. Deploy trong vài giây. ✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentation](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div>
---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
---
# Reflex
Reflex là một thư viện để xây dựng ứng dụng web toàn bộ bằng Python thuần.
Các tính năng chính:
* **Python thuần tuý** - Viết toàn bộ ứng dụng cả backend và frontend hoàn toàn bằng Python, không cần học JavaScript.
* **Full Flexibility** - Reflex dễ dàng để bắt đầu, nhưng cũng có thể mở rộng lên các ứng dụng phức tạp.
* **Deploy Instantly** - Sau khi xây dựng ứng dụng, bạn có thể triển khai bằng [một dòng lệnh](https://reflex.dev/docs/hosting/deploy-quick-start/) hoặc triển khai trên server của riêng bạn.
Đọc [bài viết về kiến trúc hệ thống](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) để hiểu rõ các hoạt động của Reflex.
## ⚙️ Cài đặt
Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.10+):
```bash
pip install reflex
```
## 🥳 Tạo ứng dụng đầu tiên
Cài đặt `reflex` cũng như cài đặt công cụ dòng lệnh `reflex`.
Kiểm tra việc cài đặt đã thành công hay chưa bằng cách tạo mới một ứng dụng. (Thay `my_app_name` bằng tên ứng dụng của bạn):
```bash
mkdir my_app_name
cd my_app_name
reflex init
```
Lệnh này tạo ra một ứng dụng mẫu trong một thư mục mới.
Bạn có thể chạy ứng dụng ở chế độ phát triển.
```bash
reflex run
```
Bạn có thể xem ứng dụng của bạn ở địa chỉ http://localhost:3000.
Bạn có thể thay đổi mã nguồn ở `my_app_name/my_app_name.py`. Reflex nhanh chóng làm mới và bạn có thể thấy thay đổi trên ứng dụng của bạn ngay lập tức khi bạn lưu file.
## 🫧 Ứng dụng ví dụ
Bắt đầu với ví dụ: tạo một ứng dụng tạo ảnh bằng [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Để cho đơn giản, chúng ta sẽ sử dụng [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), nhưng bạn có thể sử dụng model của chính bạn được triển khai trên local.
&nbsp;
<div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div>
&nbsp;
Đây là toàn bộ đoạn mã để xây dựng ứng dụng trên. Nó được viết hoàn toàn trong một file Python!
```python
import reflex as rx
import openai
openai_client = openai.OpenAI()
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index():
return rx.center(
rx.vstack(
rx.heading("DALL-E", font_size="1.5em"),
rx.input(
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button(
"Generate Image",
on_click=State.get_image,
width="25em",
loading=State.processing
),
rx.cond(
State.complete,
rx.image(src=State.image_url, width="20em"),
),
align="center",
),
width="100%",
height="100vh",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Reflex:DALL-E")
```
## Hãy phân tích chi tiết.
<div align="center">
<img src="../images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
</div>
### **Reflex UI**
Bắt đầu với giao diện chính.
```python
def index():
return rx.center(
...
)
```
Hàm `index` định nghĩa phần giao diện chính của ứng dụng.
Chúng tôi sử dụng các component (thành phần) khác nhau như `center`, `vstack`, `input``button` để xây dựng giao diện phía trước.
Các component có thể được lồng vào nhau để tạo ra các bố cục phức tạp. Và bạn cũng có thể sử dụng từ khoá `args` để tận dụng đầy đủ sức mạnh của CSS.
Reflex có đến hơn [60 component được xây dựng sẵn](https://reflex.dev/docs/library) để giúp bạn bắt đầu. Chúng ta có thể tạo ra một component mới khá dễ dàng, thao khảo: [xây dựng component của riêng bạn](https://reflex.dev/docs/wrapping-react/overview/).
### **State**
Reflex biểu diễn giao diện bằng các hàm của state (trạng thái).
```python
class State(rx.State):
"""The app state."""
prompt = ""
image_url = ""
processing = False
complete = False
```
Một state định nghĩa các biến (được gọi là vars) có thể thay đổi trong một ứng dụng và cho phép các hàm có thể thay đổi chúng.
Tại đây state được cấu thành từ một `prompt``image_url`.
Có cũng những biến boolean `processing``complete`
để chỉ ra khi nào tắt nút (trong quá trình tạo hình ảnh)
và khi nào hiển thị hình ảnh kết quả.
### **Event Handlers**
```python
def get_image(self):
"""Get the image from the prompt."""
if self.prompt == "":
return rx.window_alert("Prompt Empty")
self.processing, self.complete = True, False
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
```
Với các state, chúng ta định nghĩa các hàm có thể thay đổi state vars được gọi là event handlers. Event handler là cách chúng ta có thể thay đổi state trong Reflex. Chúng có thể là phản hồi khi người dùng thao tác, chằng hạn khi nhấn vào nút hoặc khi đang nhập trong text box. Các hành động này được gọi là event.
Ứng dụng DALL·E. của chúng ta có một event handler, `get_image` để lấy hình ảnh từ OpenAI API. Sử dụng từ khoá `yield` in ở giữa event handler để cập nhật giao diện. Hoặc giao diện có thể cập nhật ở cuối event handler.
### **Routing**
Cuối cùng, chúng ta định nghĩa một ứng dụng.
```python
app = rx.App()
```
Chúng ta thêm một trang ở đầu ứng dụng bằng index component. Chúng ta cũng thêm tiêu đề của ứng dụng để hiển thị lên trình duyệt.
```python
app.add_page(index, title="DALL-E")
```
Bạn có thể tạo một ứng dụng nhiều trang bằng cách thêm trang.
## 📑 Tài liệu
<div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp;
</div>
## ✅ Status
Reflex phát hành vào tháng 12/2022 với tên là Pynecone.
Đến tháng 02/2024, chúng tôi tạo ra dịch vụ dưới phiên bản alpha! Trong thời gian này mọi người có thể triển khai ứng dụng hoàn toàn miễn phí. Xem [roadmap](https://github.com/reflex-dev/reflex/issues/2727) để biết thêm chi tiết.
Reflex ra phiên bản mới với các tính năng mới hàng tuần! Hãy :star: star và :eyes: watch repo này để thấy các cập nhật mới nhất.
## Contributing
Chúng tôi chào đón mọi đóng góp dù lớn hay nhỏ. Dưới đây là các cách để bắt đầu với cộng đồng Reflex.
- **Discord**: [Discord](https://discord.gg/T5WSbC2YtQ) của chúng tôi là nơi tốt nhất để nhờ sự giúp đỡ và thảo luận các bạn có thể đóng góp.
- **GitHub Discussions**: Là cách tốt nhất để thảo luận về các tính năng mà bạn có thể đóng góp hoặc những điều bạn chưa rõ.
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) là nơi tốt nhất để thông báo. Ngoài ra bạn có thể sửa chữa các vấn đề bằng cách tạo PR.
Chúng tôi luôn sẵn sàng tìm kiếm các contributor, bất kể kinh nghiệm. Để tham gia đóng góp, xin mời xem
[CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
## Xin cảm ơn các Contributors:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## License
Reflex là mã nguồn mở và sử dụng giấy phép [Apache License 2.0](LICENSE).

View File

@ -1,159 +1,147 @@
```diff
+ 寻找 Pynecone 吗?您来对了.Pynecone 已经更名为 Reflex.+
```
<div align="center"> <div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
<img src="../../images/cones.png">
<hr> <hr>
### **✨ 使用 Python 创建高效且可自定义的网页应用程序,几秒钟内即可部署.✨** **✨ 使用 Python 创建高效且可自订的网页应用程序,几秒钟内即可部署。**
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy)
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex) [![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg) ![tests](https://github.com/pynecone-io/pynecone/actions/workflows/build.yml/badge.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction) ![versions](https://img.shields.io/pypi/pyversions/reflex-dev.svg)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ) [![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div> </div>
--- ### 不同语言的 README
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
--- ---
# Reflex [English](../../../README.md) | [简体中文](README.md) | [繁体中文](../zh_tw/README.md)
Reflex 是一个使用纯Python构建全栈web应用的库。 ---
关键特性: ## 📦 1. 安装
* **纯Python** - 前端、后端开发全都使用Python不需要学习Javascript。
* **完整的灵活性** - Reflex很容易上手, 并且也可以扩展到复杂的应用程序。
* **立即部署** - 构建后,使用[单个命令](https://reflex.dev/docs/hosting/deploy-quick-start/)就能部署应用程序;或者也可以将其托管在您自己的服务器上。
请参阅我们的[架构页](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)了解Reflex如何工作。 Reflex 需要以下最低要求:
## ⚙️ 安装 - Python 3.7+
- [Node.js 16.8.0+](https://nodejs.org/en/) (不用担心,你不需要写任何 JavaScript!)
打开一个终端并且运行(要求Python3.10+): ```
```bash
pip install reflex pip install reflex
``` ```
## 🥳 创建您的第一个应用程序 ## 🥳 2. 创建你的第一个应用程序
安装 Reflex 的同时也会安装 `reflex` 命令行工具. 安装 Reflex 的同时也会安装 `rx` 命令行工具. 通过创建一个新项目来测试是否安装成功。
通过创建一个新项目来测试是否安装成功(请把 my_app_name 替代为您的项目名字): 把 my_app_name 替代为你的项目名字:
```bash ```
mkdir my_app_name mkdir my_app_name
cd my_app_name cd my_app_name
reflex init reflex init
``` ```
这段命令会在新文件夹初始化一个应用程序模板. 当你第一次运行这个命令,将会自动下载与安装 [bun](https://bun.sh/)。
您可以在开发者模式下运行这个应用程序: 这个命令会初始化一个应用程序模板在一个新的文件夹。
```bash ## 🏃 3. 运行
你可以在开发者模式运行这个应用程序:
```
reflex run reflex run
``` ```
您可以看到您的应用程序运行在 http://localhost:3000. 你可以看到你的应用程序运行在 http://localhost:3000。
现在您可以在以下位置修改代码 `my_app_name/my_app_name.py`,Reflex 拥有快速刷新(fast refresh),所以您可以在保存代码后马上看到更改. 现在在以下位置修改原代码 `my_app_name/my_app_name.py`Reflex 拥有快速重整所以你可以在保存代码后马上看到更改。
## 🫧 范例 ## 🫧 范例
让我们来看一个例子: 创建一个使用 [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node) 进行图像生成的图形界面.为了保持范例简单,我们只使用 OpenAI API,但是您可以将其替换成本地端的 ML 模型. 让我们来看一个例子: 创建一个使用 DALL·E 的图形用户接口,为了保持范例简单,我们只使用 OpenAI API但是你可以将其替换成本地端的 ML 模型。
&nbsp; &nbsp;
<div align="center"> <div align="center">
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="DALL·E的前端界面, 展示了图片生成的进程" width="550" /> <img src="../images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
</div> </div>
&nbsp; &nbsp;
这是这个范例的完整代码,只需要一个 Python 文件就可以完成! 这是上述范例的完整代码,只需要一个 Python 文件就可以完成!
```python ```python
import reflex as rx import reflex as rx
import openai import openai
openai_client = openai.OpenAI() openai.api_key = "YOUR_API_KEY"
class State(rx.State): class State(rx.State):
"""The app state.""" """应用程序状态"""
prompt = "" prompt = ""
image_url = "" image_url = ""
processing = False image_processing = False
complete = False image_made = False
def process_image(self):
"""设置图片处理旗标为 True 并设置还未产生图片"""
self.image_processing = True
self.image_made = False
def get_image(self): def get_image(self):
"""Get the image from the prompt.""" """运用 prompt 取得的参数产生图片"""
if self.prompt == "": response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
return rx.window_alert("Prompt Empty") self.image_url = response["data"][0]["url"]
self.image_processing = False
self.processing, self.complete = True, False self.image_made = True
yield
response = openai_client.images.generate(
prompt=self.prompt, n=1, size="1024x1024"
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True
def index(): def index():
return rx.center( return rx.center(
rx.vstack( rx.vstack(
rx.heading("DALL-E", font_size="1.5em"), rx.heading("DALL·E", font_size="1.5em"),
rx.input( rx.input(placeholder="Enter a prompt..", on_blur=State.set_prompt),
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button( rx.button(
"Generate Image", "产生图片",
on_click=State.get_image, on_click=[State.process_image, State.get_image],
width="25em", width="100%",
loading=State.processing
), ),
rx.divider(),
rx.cond( rx.cond(
State.complete, State.image_processing,
rx.image(src=State.image_url, width="20em"), rx.circular_progress(is_indeterminate=True),
rx.cond(
State.image_made,
rx.image(
src=State.image_url,
height="25em",
width="25em",
)
)
), ),
align="center", bg="white",
padding="2em",
shadow="lg",
border_radius="lg",
), ),
width="100%", width="100%",
height="100vh", height="100vh",
bg="radial-gradient(circle at 22% 11%,rgba(62, 180, 137,.20),hsla(0,0%,100%,0) 19%)",
) )
# Add state and page to the app. # 把状态跟页面添加到应用程序。
app = rx.App() app = rx.App(state=State)
app.add_page(index, title="Reflex:DALL-E") app.add_page(index, title="Reflex:DALL·E")
app.compile()
``` ```
### **Reflex 中的图形用户接口**
让我们分解以上步骤。
## 让我们分解以上步骤.
<div align="center">
<img src="../../images/dalle_colored_code_example.png" alt="解释 DALL-E app 的前端和后端部分的区别。" width="900" />
</div>
### **Reflex UI**
让我们从UI开始.
```python ```python
def index(): def index():
@ -162,101 +150,91 @@ def index():
) )
``` ```
这个 `index` 函数定义了应用程序的前端. 这个 `index` function 定义了应用程序的前端.
我们用不同的组件比如 `center`, `vstack`, `input`, 和 `button` 来创建前端, 组件之间可以相互嵌入,来创建复杂的布局. 我们用不同的组件像是 `center`, `vstack`, `input`, 和 `button` 来创建前端, 组件之间可以相互嵌入,来创建复杂的布局。
并且您可以使用关键字参数来使用 CSS 的全部功能. 并且你可以使用关键字参数来使用 CSS 的全部功能。
Reflex 拥有 [60+ 个内置组件](https://reflex.dev/docs/library) 来帮助您开始创建应用程序. 我们正在积极添加组件, 但是您也可以容易的 [创建自己的组件](https://reflex.dev/docs/wrapping-react/overview/). Reflex 拥有 [60+ built-in components](https://reflex.dev/docs/library) 来帮助你开始创建应用程序。
我们正在积极添加组件, 但是你也可以简单的自己创建一些组件 [create your own components](https://reflex.dev/docs/advanced-guide/wrapping-react)。
### **State** ### **状态**
Reflex 用 State 来渲染您的 UI. Reflex 用 State 来渲染你的 UI。
```python ```python
class State(rx.State): class State(rx.State):
"""The app state.""" """应用程序状态"""
prompt = "" prompt = ""
image_url = "" image_url = ""
processing = False image_processing = False
complete = False image_made = False
``` ```
State定义了所有可能会发生变化的变量(称为 vars)以及能够改变这些变量的函数. State 定义了应用程序中所有可以更改的变量及变更他们的 function (称为 vars)。
在这个范例中,State由 `prompt``image_url` 组成.此外,State还包含有两个布尔值 `processing``complete`,用于指示何时显示循环进度指示器和图像. 这里的状态由 `prompt``image_url`组成, 以及布尔变量 `image_processing``image_made` 来决定何时显示进度条及图片。
### **Event Handlers** ### **事件处理进程**
```python ```python
def get_image(self): def process_image(self):
"""Get the image from the prompt.""" """设置图片处理旗标为 True 并设置还未产生图片"""
if self.prompt == "": self.image_processing = True
return rx.window_alert("Prompt Empty") self.image_made = False
self.processing, self.complete = True, False def get_image(self):
yield """运用 prompt 取得的参数产生图片"""
response = openai_client.images.generate( response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
prompt=self.prompt, n=1, size="1024x1024" self.image_url = response["data"][0]["url"]
) self.image_processing = False
self.image_url = response.data[0].url self.image_made = True
self.processing, self.complete = False, True
``` ```
在 State 中,我们定义了称为事件处理器(event handlers)的函数,用于改变状态变量(state vars).在Reflex中,事件处理器是我们可以修改状态的方式.它们可以作为对用户操作的响应而被调用,例如点击一个按钮或在文本框中输入.这些操作被称为事件. 在 State 中我们定义了事件处理进程来更改状态变量,事件处理进程是我们在 Reflex 中修改状态的方法,可以使用它们来回应用户操作,像是点击按钮或在文本框输入这些动作都是一种事件。
我们的DALL·E应用有一个事件处理器,名为 `get_image`,它用于从OpenAI API获取图像.在事件处理器中使用 `yield` 将导致UI进行更新.否则,UI将在事件处理器结束时进行更新. 我们的 DALL·E. 应用程序有两个事件处理进程 `process_image` 表示正在生成图片和 `get_image` 调用 OpenAI API。
### **Routing** ### **路由**
最后,定义我们的应用程序. 最后定义我们的应用程序并发送状态给它。
```python ```python
app = rx.App() app = rx.App(state=State)
``` ```
我们添加从应用程序根目录到 index 组件的路由.我们还添加了一个在页面预览或浏览器标签中显示的标题. 添加从应用程序根目录到 index 组件的路由。 我们也添加了一个标题将会显示在 预览/浏览 分页。
```python ```python
app.add_page(index, title="DALL-E") app.add_page(index, title="Reflex:DALL-E")
app.compile()
``` ```
您可以通过增加更多页面来创建一个多页面的应用. 你可以借由通过添加路由来增加更多页面。
## 📑 资源 ## Reflex 状态
<div align="center"> Reflex 于 2022 年 12 月推出。
📑 [文档](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [日志](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [组件库](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [展览](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [部署](https://reflex.dev/docs/hosting/deploy) &nbsp; 截至 2023 年 3 月,我们处于 **Public Beta** 阶段。
</div> - :white_check_mark: **Public Alpha**: 任何人都可以安装与使用 Reflex或许包含问题 但我们正在积极的解决他们。
- :large_orange_diamond: **Public Beta**: 对于非软件产品来说足够稳定。
- **Public Hosting Beta**: _Optionally_, 部属跟托管你的 Reflex!
- **Public**: 这版本的 Reflex 是可用于软件产品的。
Reflex 每周都有新功能和发布新版本! 确保你按下 :star: 和 :eyes: watch 这个 repository 来确保知道最新信息。
## ✅ Reflex 的状态
Reflex 于 2022 年 12 月以Pynecone的名称推出.
截至2024年2月我们的托管服务处于alpha测试阶段在此期间任何人都可以免费部署他们的应用程序。请查看我们的[路线图](https://github.com/reflex-dev/reflex/issues/2727)以了解我们的计划。
Reflex 每周都有新功能和发布新版本! 确保您按下 :star: 收藏和 :eyes: 关注 这个 仓库来确保知道最新信息.
## 贡献 ## 贡献
我们欢迎任何大小的贡献,以下是几个好的方法来加入 Reflex 社群. 我们欢迎任何大小的贡献,以下是几个好的方法来加入 Reflex 社群。
- **加入我们的 Discord**: 我们的 [Discord](https://discord.gg/T5WSbC2YtQ) 是帮助您加入 Reflex 项目和讨论或贡献最棒的地方. - **加入我们的 Discord**: 我们的 [Discord](https://discord.gg/T5WSbC2YtQ) 是帮助你加入 Reflex 项目和讨论或贡献最棒的地方。
- **GitHub Discussions**: 一个来讨论您想要添加的功能或是需要澄清的事情的好地方. - **GitHub Discussions**: 一个来讨论你想要添加的功能或是需要澄清的事情的好地方。
- **GitHub Issues**: [报告错误](https://github.com/reflex-dev/reflex/issues)的绝佳地方,另外您可以试着解决一些 issue 和送出 PR. - **GitHub Issues**: 报告错误的绝佳地方,另外你可以试着解决一些 issue 和送出 PR。
我们正在积极寻找贡献者,无关您的技能或经验水平. 我们正在积极寻找贡献者,无关你的技能或经验水平。
## 感谢我们所有的贡献者:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## 授权 ## 授权
Reflex 是一个开源项目,使用 [Apache License 2.0](LICENSE) 授权. Reflex 是一个开源项目且使用 [Apache License 2.0](LICENSE) 授权。

View File

@ -11,32 +11,18 @@
**✨ 使用 Python 建立高效且可自訂的網頁應用程式,幾秒鐘內即可部署。✨** **✨ 使用 Python 建立高效且可自訂的網頁應用程式,幾秒鐘內即可部署。✨**
[![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex) [![PyPI version](https://badge.fury.io/py/reflex.svg)](https://badge.fury.io/py/reflex)
![tests](https://github.com/pynecone-io/pynecone/actions/workflows/integration.yml/badge.svg)
![versions](https://img.shields.io/pypi/pyversions/reflex.svg) ![versions](https://img.shields.io/pypi/pyversions/reflex.svg)
[![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction) [![Documentaiton](https://img.shields.io/badge/Documentation%20-Introduction%20-%20%23007ec6)](https://reflex.dev/docs/getting-started/introduction)
[![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ) [![Discord](https://img.shields.io/discord/1029853095527727165?color=%237289da&label=Discord)](https://discord.gg/T5WSbC2YtQ)
</div> </div>
--- ---
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md)
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
--- ---
# Reflex
Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫。
主要特色:
* **純 Python** - 您可以用 Python 撰寫應用程式的前端和後端,無需學習 Javascript。
* **完全靈活性** - Reflex 易於上手,但也可以擴展到複雜的應用程式。
* **立即部署** - 構建後,只需使用[單一指令](https://reflex.dev/docs/hosting/deploy-quick-start/)即可部署您的應用程式,或在您自己的伺服器上託管。
請參閱我們的[架構頁面](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture)了解 Reflex 如何在底層運作。
## ⚙️ 安裝 ## ⚙️ 安裝
開啟一個終端機並且執行 (需要 Python 3.10+): 開啟一個終端機並且執行 (需要 Python 3.7+):
```bash ```bash
pip install reflex pip install reflex
@ -84,8 +70,7 @@ reflex run
import reflex as rx import reflex as rx
import openai import openai
openai_client = openai.OpenAI() openai.api_key = "YOUR_API_KEY"
class State(rx.State): class State(rx.State):
"""應用程式狀態""" """應用程式狀態"""
@ -101,33 +86,33 @@ class State(rx.State):
self.processing, self.complete = True, False self.processing, self.complete = True, False
yield yield
response = openai_client.images.generate( response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
prompt=self.prompt, n=1, size="1024x1024" self.image_url = response["data"][0]["url"]
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True self.processing, self.complete = False, True
def index(): def index():
return rx.center( return rx.center(
rx.vstack( rx.vstack(
rx.heading("DALL-E", font_size="1.5em"), rx.heading("DALL·E"),
rx.input( rx.input(placeholder="Enter a prompt", on_blur=State.set_prompt),
placeholder="Enter a prompt..",
on_blur=State.set_prompt,
width="25em",
),
rx.button( rx.button(
"Generate Image", "Generate Image",
on_click=State.get_image, on_click=State.get_image,
width="25em", is_loading=State.processing,
loading=State.processing width="100%",
), ),
rx.cond( rx.cond(
State.complete, State.complete,
rx.image(src=State.image_url, width="20em"), rx.image(
src=State.image_url,
height="25em",
width="25em",
)
), ),
align="center", padding="2em",
shadow="lg",
border_radius="lg",
), ),
width="100%", width="100%",
height="100vh", height="100vh",
@ -135,22 +120,11 @@ def index():
# 把狀態跟頁面添加到應用程式。 # 把狀態跟頁面添加到應用程式。
app = rx.App() app = rx.App()
app.add_page(index, title="Reflex:DALL-E") app.add_page(index, title="reflex:DALL·E")
app.compile()
``` ```
## 讓我們來拆解一下。 ## 讓我們來拆解一下。
<div align="center">
<img src="../../images/dalle_colored_code_example.png" alt="解釋 DALL-E app 的前端和後端部分的區別。" width="900" />
</div>
### **Reflex 使用者介面** ### **Reflex 使用者介面**
讓我們從使用介面開始。 讓我們從使用介面開始。
@ -166,7 +140,7 @@ def index():
我們用不同的元件像是 `center`, `vstack`, `input`, 和 `button` 來建立前端,元件之間可互相套入以建立出複雜的版面配置。並且您可使用關鍵字引數 *keyword args* 運行 CSS 全部功能來設計這些元件們的樣式。 我們用不同的元件像是 `center`, `vstack`, `input`, 和 `button` 來建立前端,元件之間可互相套入以建立出複雜的版面配置。並且您可使用關鍵字引數 *keyword args* 運行 CSS 全部功能來設計這些元件們的樣式。
Reflex 擁有 [60+ 內建元件](https://reflex.dev/docs/library) 來幫助你開始建立應用程式。我們正積極添加元件,你也可以簡單地 [創建自己所屬的元件](https://reflex.dev/docs/wrapping-react/overview/)。 Reflex 擁有 [60+ 內建元件](https://reflex.dev/docs/library) 來幫助你開始建立應用程式。我們正積極添加元件,你也可以簡單地 [創建自己所屬的元件](https://reflex.dev/docs/advanced-guide/wrapping-react)。
### **應用程式狀態** ### **應用程式狀態**
@ -177,9 +151,8 @@ class State(rx.State):
"""應用程式狀態""" """應用程式狀態"""
prompt = "" prompt = ""
image_url = "" image_url = ""
processing = False image_processing = False
complete = False image_made = False
``` ```
應用程式狀態定義了應用程式中所有可以更改的變數及變更他們的函式 (稱為 vars)。 應用程式狀態定義了應用程式中所有可以更改的變數及變更他們的函式 (稱為 vars)。
@ -196,10 +169,8 @@ def get_image(self):
self.processing, self.complete = True, False self.processing, self.complete = True, False
yield yield
response = openai_client.images.generate( response = openai.Image.create(prompt=self.prompt, n=1, size="1024x1024")
prompt=self.prompt, n=1, size="1024x1024" self.image_url = response["data"][0]["url"]
)
self.image_url = response.data[0].url
self.processing, self.complete = False, True self.processing, self.complete = False, True
``` ```
@ -221,6 +192,7 @@ app = rx.App()
```python ```python
app.add_page(index, title="DALL-E") app.add_page(index, title="DALL-E")
app.compile()
``` ```
你可以添加更多頁面至路由藉此來建立多頁面應用程式(multi-page app) 你可以添加更多頁面至路由藉此來建立多頁面應用程式(multi-page app)
@ -229,35 +201,34 @@ app.add_page(index, title="DALL-E")
<div align="center"> <div align="center">
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Templates](https://reflex.dev/templates/) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start) &nbsp; 📑 [Docs](https://reflex.dev/docs/getting-started/introduction) &nbsp; | &nbsp; 🗞️ [Blog](https://reflex.dev/blog) &nbsp; | &nbsp; 📱 [Component Library](https://reflex.dev/docs/library) &nbsp; | &nbsp; 🖼️ [Gallery](https://reflex.dev/docs/gallery) &nbsp; | &nbsp; 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy) &nbsp;
</div> </div>
## ✅ 產品狀態 ## ✅ Reflex 狀態
Reflex 在 2022 年 12 月以 Pynecone 的名字推出 Reflex 於 2022 年 12 月推出,當時名為 Pynecone
截至 2024 年 2 月,我們的託管服務已進入 alpha 階段!在此期間,任何人都可以免費部署他們的應用程式。請參閱我們的[產品地圖](https://github.com/reflex-dev/reflex/issues/2727)了解未來的計劃。 截至 2023 年 7 月,我們處於 **Public Beta** 階段。
- :white_check_mark: **Public Alpha**: 任何人都可以安裝與使用 Reflex或許包含問題 但我們正在積極的解決他們。
- :large_orange_diamond: **Public Beta**: 對於不涉及商業目的使用情境來說足夠穩定。
- **Public Hosting Beta**: _Optionally_, 部屬跟託管你的 Reflex!
- **Public**: 這版本的 Reflex 是可用於軟體產品的。
Reflex 每周都有新功能和釋出新版本! 確保你按下 :star: 和 :eyes: watch 這個 repository 來確保知道最新資訊。 Reflex 每周都有新功能和釋出新版本! 確保你按下 :star: 和 :eyes: watch 這個 repository 來確保知道最新資訊。
## 貢獻 ## 貢獻
我們歡迎任何大小的貢獻,以下是一些加入 Reflex 社群的好方法 我們歡迎任何大小的貢獻,以下是幾個好的方法來加入 Reflex 社群
- **加入我們的 Discord**: 我們的 [Discord](https://discord.gg/T5WSbC2YtQ) 是獲取 Reflex 專案幫助和討論如何貢獻的最佳地方。 - **加入我們的 Discord**: 我們的 [Discord](https://discord.gg/T5WSbC2YtQ) 是幫助你加入 Reflex 專案和討論或貢獻最棒的地方。
- **GitHub Discussions**: 這是一個討論您想新增的功能或對於一些困惑/需要澄清事項的好方法 - **GitHub Discussions**: 一個來討論你想要添加的功能或是需要澄清的事情的好地方
- **GitHub Issues**: 在 [Issues](https://github.com/reflex-dev/reflex/issues) 頁面報告錯誤是一個絕佳的方式。此外,您也可以嘗試解決現有 Issue 並提交 PR。 - **GitHub Issues**: 報告錯誤的絕佳地方,另外你可以試著解決一些 issue 和送出 PR。
我們積極尋找貢獻者,不論您的技能水平或經驗如何。要貢獻,請查看 [CONTRIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md) 我們正在積極尋找貢獻者,無關你的技能水平或經驗。
## 感謝所有貢獻者:
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
</a>
## 授權 ## 授權

59
integration/conftest.py Normal file
View File

@ -0,0 +1,59 @@
"""Shared conftest for all integration tests."""
import os
import re
from pathlib import Path
import pytest
DISPLAY = None
XVFB_DIMENSIONS = (800, 600)
@pytest.fixture(scope="session", autouse=True)
def xvfb():
"""Create virtual X display.
This function is a no-op unless GITHUB_ACTIONS is set in the environment.
Yields:
the pyvirtualdisplay object that the browser will be open on
"""
if os.environ.get("GITHUB_ACTIONS"):
from pyvirtualdisplay.smartdisplay import ( # pyright: ignore [reportMissingImports]
SmartDisplay,
)
global DISPLAY
with SmartDisplay(visible=0, size=XVFB_DIMENSIONS) as DISPLAY:
yield DISPLAY
DISPLAY = None
else:
yield None
def pytest_exception_interact(node, call, report):
"""Take and upload screenshot when tests fail.
Args:
node: The pytest item that failed.
call: The pytest call describing when/where the test was invoked.
report: The pytest log report object.
"""
screenshot_dir = os.environ.get("SCREENSHOT_DIR")
if DISPLAY is None or screenshot_dir is None:
return
screenshot_dir = Path(screenshot_dir)
screenshot_dir.mkdir(parents=True, exist_ok=True)
safe_filename = re.sub(
r"(?u)[^-\w.]",
"_",
str(node.nodeid).strip().replace(" ", "_").replace(":", "_"),
)
try:
DISPLAY.waitgrab().save(
(Path(screenshot_dir) / safe_filename).with_suffix(".png"),
)
except Exception as e:
print(f"Failed to take screenshot for {node}: {e}")

View File

@ -0,0 +1,21 @@
FROM ubuntu:latest
ARG USERNAME=kerrigan
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
#
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
&& apt-get update \
&& apt-get install -y sudo curl xz-utils python3 python3-pip python3.10-venv unzip \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME
USER $USERNAME
RUN curl -sSL https://install.python-poetry.org | python3 -
RUN sudo ln -s /home/$USERNAME/.local/bin/poetry /usr/local/bin/poetry
WORKDIR /home/$USERNAME

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -ex
echo "Preparing test project dir"
mkdir hello
python3 -m venv ~/hello/venv
source ~/hello/venv/bin/activate
echo "Installing reflex from local repo code"
cd /reflex-repo
poetry install
echo "Running reflex init in test project dir"
poetry run /bin/bash -c "cd ~/hello && reflex init && rm -rf ~/.reflex .web && reflex export --backend-only"

View File

@ -0,0 +1,190 @@
"""Integration tests for dynamic route page behavior."""
import time
from contextlib import contextmanager
from typing import Generator
from urllib.parse import urlsplit
import pytest
from selenium.webdriver.common.by import By
from reflex.testing import AppHarness
def DynamicRoute():
"""App for testing dynamic routes."""
import reflex as rx
class DynamicState(rx.State):
order: list[str] = []
page_id: str = ""
def on_load(self):
self.order.append(self.page_id or "no page id")
@rx.var
def next_page(self) -> str:
try:
return str(int(self.page_id) + 1)
except ValueError:
return "0"
@rx.var
def token(self) -> str:
return self.get_token()
def index():
return rx.fragment(
rx.input(value=DynamicState.token, is_read_only=True, id="token"),
rx.input(value=DynamicState.page_id, is_read_only=True, id="page_id"),
rx.link("index", href="/", id="link_index"),
rx.link("page_X", href="/static/x", id="link_page_x"),
rx.link(
"next", href="/page/" + DynamicState.next_page, id="link_page_next" # type: ignore
),
rx.list(
rx.foreach(DynamicState.order, lambda i: rx.list_item(rx.text(i))), # type: ignore
),
)
app = rx.App(state=DynamicState)
app.add_page(index)
app.add_page(index, route="/page/[page_id]", on_load=DynamicState.on_load) # type: ignore
app.add_page(index, route="/static/x", on_load=DynamicState.on_load) # type: ignore
app.compile()
@pytest.fixture(scope="session")
def dynamic_route(tmp_path_factory) -> Generator[AppHarness, None, None]:
"""Start DynamicRoute app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path_factory.mktemp("dynamic_route"),
app_source=DynamicRoute, # type: ignore
) as harness:
yield harness
@pytest.fixture
def driver(dynamic_route: AppHarness):
"""Get an instance of the browser open to the dynamic_route app.
Args:
dynamic_route: harness for DynamicRoute app
Yields:
WebDriver instance.
"""
assert dynamic_route.app_instance is not None, "app is not running"
driver = dynamic_route.frontend()
try:
assert dynamic_route.poll_for_clients()
yield driver
finally:
driver.quit()
@contextmanager
def poll_for_navigation(driver, timeout: int = 5) -> Generator[None, None, None]:
"""Wait for driver url to change.
Use as a contextmanager, and apply the navigation event inside the context
block, polling will occur after the context block exits.
Args:
driver: WebDriver instance.
timeout: Time to wait for url to change.
Yields:
None
"""
prev_url = driver.current_url
yield
AppHarness._poll_for(lambda: prev_url != driver.current_url, timeout=timeout)
def test_on_load_navigate(dynamic_route: AppHarness, driver):
"""Click links to navigate between dynamic pages with on_load event.
Args:
dynamic_route: harness for DynamicRoute app.
driver: WebDriver instance.
"""
assert dynamic_route.app_instance is not None
token_input = driver.find_element(By.ID, "token")
link = driver.find_element(By.ID, "link_page_next")
assert token_input
assert link
# wait for the backend connection to send the token
token = dynamic_route.poll_for_value(token_input)
assert token is not None
# click the link a few times
for ix in range(10):
# wait for navigation, then assert on url
with poll_for_navigation(driver):
link.click()
assert urlsplit(driver.current_url).path == f"/page/{ix}/"
link = driver.find_element(By.ID, "link_page_next")
page_id_input = driver.find_element(By.ID, "page_id")
assert link
assert page_id_input
assert dynamic_route.poll_for_value(page_id_input) == str(ix)
# look up the backend state and assert that `on_load` was called for all
# navigation events
backend_state = dynamic_route.app_instance.state_manager.states[token]
time.sleep(0.2)
assert backend_state.order == [str(ix) for ix in range(10)]
def test_on_load_navigate_non_dynamic(dynamic_route: AppHarness, driver):
"""Click links to navigate between static pages with on_load event.
Args:
dynamic_route: harness for DynamicRoute app.
driver: WebDriver instance.
"""
assert dynamic_route.app_instance is not None
token_input = driver.find_element(By.ID, "token")
link = driver.find_element(By.ID, "link_page_x")
assert token_input
assert link
# wait for the backend connection to send the token
token = dynamic_route.poll_for_value(token_input)
assert token is not None
with poll_for_navigation(driver):
link.click()
assert urlsplit(driver.current_url).path == "/static/x/"
# look up the backend state and assert that `on_load` was called once
backend_state = dynamic_route.app_instance.state_manager.states[token]
time.sleep(0.2)
assert backend_state.order == ["no page id"]
# go back to the index and navigate back to the static route
link = driver.find_element(By.ID, "link_index")
with poll_for_navigation(driver):
link.click()
assert urlsplit(driver.current_url).path == "/"
link = driver.find_element(By.ID, "link_page_x")
with poll_for_navigation(driver):
link.click()
assert urlsplit(driver.current_url).path == "/static/x/"
time.sleep(0.2)
assert backend_state.order == ["no page id", "no page id"]

View File

@ -0,0 +1,332 @@
"""Ensure that Event Chains are properly queued and handled between frontend and backend."""
import time
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from reflex.testing import AppHarness
MANY_EVENTS = 50
def EventChain():
"""App with chained event handlers."""
import reflex as rx
# repeated here since the outer global isn't exported into the App module
MANY_EVENTS = 50
class State(rx.State):
event_order: list[str] = []
@rx.var
def token(self) -> str:
return self.get_token()
def event_no_args(self):
self.event_order.append("event_no_args")
def event_arg(self, arg):
self.event_order.append(f"event_arg:{arg}")
def event_nested_1(self):
self.event_order.append("event_nested_1")
yield State.event_nested_2
yield State.event_arg("nested_1") # type: ignore
def event_nested_2(self):
self.event_order.append("event_nested_2")
yield State.event_nested_3
yield rx.console_log("event_nested_2")
yield State.event_arg("nested_2") # type: ignore
def event_nested_3(self):
self.event_order.append("event_nested_3")
yield State.event_no_args
yield State.event_arg("nested_3") # type: ignore
def on_load_return_chain(self):
self.event_order.append("on_load_return_chain")
return [State.event_arg(1), State.event_arg(2), State.event_arg(3)] # type: ignore
def on_load_yield_chain(self):
self.event_order.append("on_load_yield_chain")
yield State.event_arg(4) # type: ignore
yield State.event_arg(5) # type: ignore
yield State.event_arg(6) # type: ignore
def click_return_event(self):
self.event_order.append("click_return_event")
return State.event_no_args
def click_return_events(self):
self.event_order.append("click_return_events")
return [
State.event_arg(7), # type: ignore
rx.console_log("click_return_events"),
State.event_arg(8), # type: ignore
State.event_arg(9), # type: ignore
]
def click_yield_chain(self):
self.event_order.append("click_yield_chain:0")
yield State.event_arg(10) # type: ignore
self.event_order.append("click_yield_chain:1")
yield rx.console_log("click_yield_chain")
yield State.event_arg(11) # type: ignore
self.event_order.append("click_yield_chain:2")
yield State.event_arg(12) # type: ignore
self.event_order.append("click_yield_chain:3")
def click_yield_many_events(self):
self.event_order.append("click_yield_many_events")
for ix in range(MANY_EVENTS):
yield State.event_arg(ix) # type: ignore
yield rx.console_log(f"many_events_{ix}")
self.event_order.append("click_yield_many_events_done")
def click_yield_nested(self):
self.event_order.append("click_yield_nested")
yield State.event_nested_1
yield State.event_arg("yield_nested") # type: ignore
def redirect_return_chain(self):
self.event_order.append("redirect_return_chain")
yield rx.redirect("/on-load-return-chain")
def redirect_yield_chain(self):
self.event_order.append("redirect_yield_chain")
yield rx.redirect("/on-load-yield-chain")
app = rx.App(state=State)
@app.add_page
def index():
return rx.fragment(
rx.input(value=State.token, readonly=True, id="token"),
rx.button(
"Return Event",
id="return_event",
on_click=State.click_return_event,
),
rx.button(
"Return Events",
id="return_events",
on_click=State.click_return_events,
),
rx.button(
"Yield Chain",
id="yield_chain",
on_click=State.click_yield_chain,
),
rx.button(
"Yield Many events",
id="yield_many_events",
on_click=State.click_yield_many_events,
),
rx.button(
"Yield Nested",
id="yield_nested",
on_click=State.click_yield_nested,
),
rx.button(
"Redirect Yield Chain",
id="redirect_yield_chain",
on_click=State.redirect_yield_chain,
),
rx.button(
"Redirect Return Chain",
id="redirect_return_chain",
on_click=State.redirect_return_chain,
),
)
def on_load_return_chain():
return rx.fragment(
rx.text("return"),
rx.input(value=State.token, readonly=True, id="token"),
)
def on_load_yield_chain():
return rx.fragment(
rx.text("yield"),
rx.input(value=State.token, readonly=True, id="token"),
)
app.add_page(on_load_return_chain, on_load=State.on_load_return_chain) # type: ignore
app.add_page(on_load_yield_chain, on_load=State.on_load_yield_chain) # type: ignore
app.compile()
@pytest.fixture(scope="session")
def event_chain(tmp_path_factory) -> Generator[AppHarness, None, None]:
"""Start EventChain app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path_factory.mktemp("event_chain"),
app_source=EventChain, # type: ignore
) as harness:
yield harness
@pytest.fixture
def driver(event_chain: AppHarness):
"""Get an instance of the browser open to the event_chain app.
Args:
event_chain: harness for EventChain app
Yields:
WebDriver instance.
"""
assert event_chain.app_instance is not None, "app is not running"
driver = event_chain.frontend()
try:
assert event_chain.poll_for_clients()
yield driver
finally:
driver.quit()
@pytest.mark.parametrize(
("button_id", "exp_event_order"),
[
("return_event", ["click_return_event", "event_no_args"]),
(
"return_events",
["click_return_events", "event_arg:7", "event_arg:8", "event_arg:9"],
),
(
"yield_chain",
[
"click_yield_chain:0",
"click_yield_chain:1",
"click_yield_chain:2",
"click_yield_chain:3",
"event_arg:10",
"event_arg:11",
"event_arg:12",
],
),
(
"yield_many_events",
[
"click_yield_many_events",
"click_yield_many_events_done",
*[f"event_arg:{ix}" for ix in range(MANY_EVENTS)],
],
),
(
"yield_nested",
[
"click_yield_nested",
"event_nested_1",
"event_arg:yield_nested",
"event_nested_2",
"event_arg:nested_1",
"event_nested_3",
"event_arg:nested_2",
"event_no_args",
"event_arg:nested_3",
],
),
(
"redirect_return_chain",
[
"redirect_return_chain",
"on_load_return_chain",
"event_arg:1",
"event_arg:2",
"event_arg:3",
],
),
(
"redirect_yield_chain",
[
"redirect_yield_chain",
"on_load_yield_chain",
"event_arg:4",
"event_arg:5",
"event_arg:6",
],
),
],
)
def test_event_chain_click(event_chain, driver, button_id, exp_event_order):
"""Click the button, assert that the events are handled in the correct order.
Args:
event_chain: AppHarness for the event_chain app
driver: selenium WebDriver open to the app
button_id: the ID of the button to click
exp_event_order: the expected events recorded in the State
"""
token_input = driver.find_element(By.ID, "token")
btn = driver.find_element(By.ID, button_id)
assert token_input
assert btn
token = event_chain.poll_for_value(token_input)
btn.click()
if "redirect" in button_id:
# wait a bit longer if we're redirecting
time.sleep(1)
if "many_events" in button_id:
# wait a bit longer if we have loads of events
time.sleep(1)
time.sleep(0.5)
backend_state = event_chain.app_instance.state_manager.states[token]
assert backend_state.event_order == exp_event_order
@pytest.mark.parametrize(
("uri", "exp_event_order"),
[
(
"/on-load-return-chain",
[
"on_load_return_chain",
"event_arg:1",
"event_arg:2",
"event_arg:3",
],
),
(
"/on-load-yield-chain",
[
"on_load_yield_chain",
"event_arg:4",
"event_arg:5",
"event_arg:6",
],
),
],
)
def test_event_chain_on_load(event_chain, driver, uri, exp_event_order):
"""Load the URI, assert that the events are handled in the correct order.
Args:
event_chain: AppHarness for the event_chain app
driver: selenium WebDriver open to the app
uri: the page to load
exp_event_order: the expected events recorded in the State
"""
driver.get(event_chain.frontend_url + uri)
token_input = driver.find_element(By.ID, "token")
assert token_input
token = event_chain.poll_for_value(token_input)
time.sleep(0.5)
backend_state = event_chain.app_instance.state_manager.states[token]
assert backend_state.event_order == exp_event_order

View File

@ -0,0 +1,141 @@
"""Integration tests for forms."""
import time
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from reflex.testing import AppHarness
def FormSubmit():
"""App with a form using on_submit."""
import reflex as rx
class FormState(rx.State):
form_data: dict = {}
def form_submit(self, form_data: dict):
self.form_data = form_data
app = rx.App(state=FormState)
@app.add_page
def index():
return rx.vstack(
rx.form(
rx.vstack(
rx.input(id="name_input"),
rx.hstack(rx.pin_input(length=4, id="pin_input")),
rx.number_input(id="number_input"),
rx.checkbox(id="bool_input"),
rx.switch(id="bool_input2"),
rx.slider(id="slider_input"),
rx.range_slider(id="range_input"),
rx.radio_group(["option1", "option2"], id="radio_input"),
rx.select(["option1", "option2"], id="select_input"),
rx.text_area(id="text_area_input"),
rx.button("Submit", type_="submit"),
),
on_submit=FormState.form_submit,
),
rx.spacer(),
height="100vh",
)
app.compile()
@pytest.fixture(scope="session")
def form_submit(tmp_path_factory) -> Generator[AppHarness, None, None]:
"""Start FormSubmit app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path_factory.mktemp("form_submit"),
app_source=FormSubmit, # type: ignore
) as harness:
assert harness.app_instance is not None, "app is not running"
yield harness
@pytest.fixture
def driver(form_submit: AppHarness):
"""GEt an instance of the browser open to the form_submit app.
Args:
form_submit: harness for ServerSideEvent app
Yields:
WebDriver instance.
"""
driver = form_submit.frontend()
try:
assert form_submit.poll_for_clients()
yield driver
finally:
driver.quit()
def test_submit(driver, form_submit: AppHarness):
"""Fill a form with various different output, submit it to backend and verify
the output.
Args:
driver: selenium WebDriver open to the app
form_submit: harness for FormSubmit app
"""
assert form_submit.app_instance is not None, "app is not running"
_, backend_state = list(form_submit.app_instance.state_manager.states.items())[0]
name_input = driver.find_element(By.ID, "name_input")
name_input.send_keys("foo")
pin_inputs = driver.find_elements(By.CLASS_NAME, "chakra-pin-input")
pin_values = ["8", "1", "6", "4"]
for i, pin_input in enumerate(pin_inputs):
pin_input.send_keys(pin_values[i])
number_input = driver.find_element(By.CLASS_NAME, "chakra-numberinput")
buttons = number_input.find_elements(By.XPATH, "//div[@role='button']")
for _ in range(3):
buttons[1].click()
checkbox_input = driver.find_element(By.CLASS_NAME, "chakra-checkbox__control")
checkbox_input.click()
switch_input = driver.find_element(By.CLASS_NAME, "chakra-switch__track")
switch_input.click()
radio_buttons = driver.find_elements(By.CLASS_NAME, "chakra-radio__control")
radio_buttons[1].click()
textarea_input = driver.find_element(By.CLASS_NAME, "chakra-textarea")
textarea_input.send_keys("Some", Keys.ENTER, "Text")
time.sleep(1)
submit_input = driver.find_element(By.CLASS_NAME, "chakra-button")
submit_input.click()
# wait for the form data to arrive at the backend
AppHarness._poll_for(
lambda: backend_state.form_data != {},
)
assert backend_state.form_data["name_input"] == "foo"
assert backend_state.form_data["pin_input"] == pin_values
assert backend_state.form_data["number_input"] == "-3"
assert backend_state.form_data["bool_input"] is True
assert backend_state.form_data["bool_input2"] is True
assert backend_state.form_data["slider_input"] == "50"
assert backend_state.form_data["range_input"] == ["25", "75"]
assert backend_state.form_data["radio_input"] == "option2"
assert backend_state.form_data["select_input"] == "option1"
assert backend_state.form_data["text_area_input"] == "Some\nText"

119
integration/test_input.py Normal file
View File

@ -0,0 +1,119 @@
"""Integration tests for text input and related components."""
import time
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from reflex.testing import AppHarness
def FullyControlledInput():
"""App using a fully controlled input with implicit debounce wrapper."""
import reflex as rx
class State(rx.State):
text: str = "initial"
app = rx.App(state=State)
@app.add_page
def index():
return rx.fragment(
rx.input(
id="debounce_input_input",
on_change=State.set_text, # type: ignore
value=State.text,
),
rx.input(value=State.text, id="value_input"),
rx.input(on_change=State.set_text, id="on_change_input"), # type: ignore
rx.button("CLEAR", on_click=rx.set_value("on_change_input", "")),
)
app.compile()
@pytest.fixture()
def fully_controlled_input(tmp_path) -> Generator[AppHarness, None, None]:
"""Start FullyControlledInput app at tmp_path via AppHarness.
Args:
tmp_path: pytest tmp_path fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path,
app_source=FullyControlledInput, # type: ignore
) as harness:
yield harness
@pytest.mark.asyncio
async def test_fully_controlled_input(fully_controlled_input: AppHarness):
"""Type text after moving cursor. Update text on backend.
Args:
fully_controlled_input: harness for FullyControlledInput app
"""
assert fully_controlled_input.app_instance is not None, "app is not running"
driver = fully_controlled_input.frontend()
# get a reference to the connected client
assert len(fully_controlled_input.poll_for_clients()) == 1
token, backend_state = list(
fully_controlled_input.app_instance.state_manager.states.items()
)[0]
# find the input and wait for it to have the initial state value
debounce_input = driver.find_element(By.ID, "debounce_input_input")
value_input = driver.find_element(By.ID, "value_input")
on_change_input = driver.find_element(By.ID, "on_change_input")
clear_button = driver.find_element(By.TAG_NAME, "button")
assert fully_controlled_input.poll_for_value(debounce_input) == "initial"
assert fully_controlled_input.poll_for_value(value_input) == "initial"
# move cursor to home, then to the right and type characters
debounce_input.send_keys(Keys.HOME, Keys.ARROW_RIGHT)
debounce_input.send_keys("foo")
time.sleep(0.5)
assert debounce_input.get_attribute("value") == "ifoonitial"
assert backend_state.text == "ifoonitial"
assert fully_controlled_input.poll_for_value(value_input) == "ifoonitial"
# clear the input on the backend
backend_state.text = ""
fully_controlled_input.app_instance.state_manager.set_state(token, backend_state)
await fully_controlled_input.emit_state_updates()
assert backend_state.text == ""
assert (
fully_controlled_input.poll_for_value(
debounce_input, exp_not_equal="ifoonitial"
)
== ""
)
# type more characters
debounce_input.send_keys("getting testing done")
time.sleep(0.5)
assert debounce_input.get_attribute("value") == "getting testing done"
assert backend_state.text == "getting testing done"
assert fully_controlled_input.poll_for_value(value_input) == "getting testing done"
# type into the on_change input
on_change_input.send_keys("overwrite the state")
time.sleep(0.5)
assert debounce_input.get_attribute("value") == "overwrite the state"
assert on_change_input.get_attribute("value") == "overwrite the state"
assert backend_state.text == "overwrite the state"
assert fully_controlled_input.poll_for_value(value_input) == "overwrite the state"
clear_button.click()
time.sleep(0.5)
assert on_change_input.get_attribute("value") == ""
# potential bug: clearing the on_change field doesn't itself trigger on_change
# assert backend_state.text == ""
# assert debounce_input.get_attribute("value") == ""
# assert value_input.get_attribute("value") == ""

View File

@ -1,5 +1,4 @@
"""Integration tests for special server side events.""" """Integration tests for special server side events."""
import time import time
from typing import Generator from typing import Generator
@ -14,19 +13,16 @@ def ServerSideEvent():
import reflex as rx import reflex as rx
class SSState(rx.State): class SSState(rx.State):
@rx.event
def set_value_yield(self): def set_value_yield(self):
yield rx.set_value("a", "") yield rx.set_value("a", "")
yield rx.set_value("b", "") yield rx.set_value("b", "")
yield rx.set_value("c", "") yield rx.set_value("c", "")
@rx.event
def set_value_yield_return(self): def set_value_yield_return(self):
yield rx.set_value("a", "") yield rx.set_value("a", "")
yield rx.set_value("b", "") yield rx.set_value("b", "")
return rx.set_value("c", "") return rx.set_value("c", "")
@rx.event
def set_value_return(self): def set_value_return(self):
return [ return [
rx.set_value("a", ""), rx.set_value("a", ""),
@ -34,18 +30,14 @@ def ServerSideEvent():
rx.set_value("c", ""), rx.set_value("c", ""),
] ]
@rx.event
def set_value_return_c(self): def set_value_return_c(self):
return rx.set_value("c", "") return rx.set_value("c", "")
app = rx.App(_state=rx.State) app = rx.App(state=SSState)
@app.add_page @app.add_page
def index(): def index():
return rx.fragment( return rx.fragment(
rx.input(
id="token", value=SSState.router.session.client_token, is_read_only=True
),
rx.input(default_value="a", id="a"), rx.input(default_value="a", id="a"),
rx.input(default_value="b", id="b"), rx.input(default_value="b", id="b"),
rx.input(default_value="c", id="c"), rx.input(default_value="c", id="c"),
@ -80,8 +72,10 @@ def ServerSideEvent():
), ),
) )
app.compile()
@pytest.fixture(scope="module")
@pytest.fixture(scope="session")
def server_side_event(tmp_path_factory) -> Generator[AppHarness, None, None]: def server_side_event(tmp_path_factory) -> Generator[AppHarness, None, None]:
"""Start ServerSideEvent app at tmp_path via AppHarness. """Start ServerSideEvent app at tmp_path via AppHarness.
@ -93,7 +87,7 @@ def server_side_event(tmp_path_factory) -> Generator[AppHarness, None, None]:
""" """
with AppHarness.create( with AppHarness.create(
root=tmp_path_factory.mktemp("server_side_event"), root=tmp_path_factory.mktemp("server_side_event"),
app_source=ServerSideEvent, app_source=ServerSideEvent, # type: ignore
) as harness: ) as harness:
yield harness yield harness
@ -102,6 +96,7 @@ def server_side_event(tmp_path_factory) -> Generator[AppHarness, None, None]:
def driver(server_side_event: AppHarness): def driver(server_side_event: AppHarness):
"""Get an instance of the browser open to the server_side_event app. """Get an instance of the browser open to the server_side_event app.
Args: Args:
server_side_event: harness for ServerSideEvent app server_side_event: harness for ServerSideEvent app
@ -111,12 +106,7 @@ def driver(server_side_event: AppHarness):
assert server_side_event.app_instance is not None, "app is not running" assert server_side_event.app_instance is not None, "app is not running"
driver = server_side_event.frontend() driver = server_side_event.frontend()
try: try:
token_input = driver.find_element(By.ID, "token") assert server_side_event.poll_for_clients()
assert token_input
# wait for the backend connection to send the token
token = server_side_event.poll_for_value(token_input)
assert token is not None
yield driver yield driver
finally: finally:
driver.quit() driver.quit()

174
integration/test_upload.py Normal file
View File

@ -0,0 +1,174 @@
"""Integration tests for file upload."""
from __future__ import annotations
import time
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from reflex.testing import AppHarness
def UploadFile():
"""App for testing dynamic routes."""
import reflex as rx
class UploadState(rx.State):
_file_data: dict[str, str] = {}
async def handle_upload(self, files: list[rx.UploadFile]):
for file in files:
upload_data = await file.read()
self._file_data[file.filename or ""] = upload_data.decode("utf-8")
@rx.var
def token(self) -> str:
return self.get_token()
def index():
return rx.vstack(
rx.input(value=UploadState.token, is_read_only=True, id="token"),
rx.upload(
rx.vstack(
rx.button("Select File"),
rx.text("Drag and drop files here or click to select files"),
),
),
rx.button(
"Upload",
on_click=lambda: UploadState.handle_upload(rx.upload_files()), # type: ignore
id="upload_button",
),
rx.box(
rx.foreach(
rx.selected_files,
lambda f: rx.text(f),
),
id="selected_files",
),
)
app = rx.App(state=UploadState)
app.add_page(index)
app.compile()
@pytest.fixture(scope="session")
def upload_file(tmp_path_factory) -> Generator[AppHarness, None, None]:
"""Start UploadFile app at tmp_path via AppHarness.
Args:
tmp_path_factory: pytest tmp_path_factory fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path_factory.mktemp("upload_file"),
app_source=UploadFile, # type: ignore
) as harness:
yield harness
@pytest.fixture
def driver(upload_file: AppHarness):
"""Get an instance of the browser open to the upload_file app.
Args:
upload_file: harness for DynamicRoute app
Yields:
WebDriver instance.
"""
assert upload_file.app_instance is not None, "app is not running"
driver = upload_file.frontend()
try:
assert upload_file.poll_for_clients()
yield driver
finally:
driver.quit()
def test_upload_file(tmp_path, upload_file: AppHarness, driver):
"""Submit a file upload and check that it arrived on the backend.
Args:
tmp_path: pytest tmp_path fixture
upload_file: harness for UploadFile app.
driver: WebDriver instance.
"""
assert upload_file.app_instance is not None
token_input = driver.find_element(By.ID, "token")
assert token_input
# wait for the backend connection to send the token
token = upload_file.poll_for_value(token_input)
assert token is not None
upload_box = driver.find_element(By.XPATH, "//input[@type='file']")
assert upload_box
upload_button = driver.find_element(By.ID, "upload_button")
assert upload_button
exp_name = "test.txt"
exp_contents = "test file contents!"
target_file = tmp_path / exp_name
target_file.write_text(exp_contents)
upload_box.send_keys(str(target_file))
upload_button.click()
# look up the backend state and assert on uploaded contents
backend_state = upload_file.app_instance.state_manager.states[token]
time.sleep(0.5)
assert backend_state._file_data[exp_name] == exp_contents
# check that the selected files are displayed
selected_files = driver.find_element(By.ID, "selected_files")
assert selected_files.text == exp_name
def test_upload_file_multiple(tmp_path, upload_file: AppHarness, driver):
"""Submit several file uploads and check that they arrived on the backend.
Args:
tmp_path: pytest tmp_path fixture
upload_file: harness for UploadFile app.
driver: WebDriver instance.
"""
assert upload_file.app_instance is not None
token_input = driver.find_element(By.ID, "token")
assert token_input
# wait for the backend connection to send the token
token = upload_file.poll_for_value(token_input)
assert token is not None
upload_box = driver.find_element(By.XPATH, "//input[@type='file']")
assert upload_box
upload_button = driver.find_element(By.ID, "upload_button")
assert upload_button
exp_files = {
"test1.txt": "test file contents!",
"test2.txt": "this is test file number 2!",
"reflex.txt": "reflex is awesome!",
}
for exp_name, exp_contents in exp_files.items():
target_file = tmp_path / exp_name
target_file.write_text(exp_contents)
upload_box.send_keys(str(target_file))
time.sleep(0.2)
# check that the selected files are displayed
selected_files = driver.find_element(By.ID, "selected_files")
assert selected_files.text == "\n".join(exp_files)
# do the upload
upload_button.click()
# look up the backend state and assert on uploaded contents
backend_state = upload_file.app_instance.state_manager.states[token]
time.sleep(0.5)
for exp_name, exp_contents in exp_files.items():
assert backend_state._file_data[exp_name] == exp_contents

3516
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +1,70 @@
[tool.poetry] [tool.poetry]
name = "reflex" name = "reflex"
version = "0.7.2dev1" version = "0.2.5"
description = "Web apps in pure Python." description = "Web apps in pure Python."
license = "Apache-2.0" license = "Apache-2.0"
authors = [ authors = [
"Nikhil Rao <nikhil@reflex.dev>", "Nikhil Rao <nikhil@reflex.dev>",
"Alek Petuskey <alek@reflex.dev>", "Alek Petuskey <alek@reflex.dev>",
"Masen Furer <masen@reflex.dev>",
"Elijah Ahianyo <elijah@reflex.dev>",
"Thomas Brandého <thomas@reflex.dev>",
] ]
readme = "README.md" readme = "README.md"
homepage = "https://reflex.dev" homepage = "https://reflex.dev"
repository = "https://github.com/reflex-dev/reflex" repository = "https://github.com/reflex-dev/reflex"
documentation = "https://reflex.dev/docs/getting-started/introduction" documentation = "https://reflex.dev/docs/getting-started/introduction"
keywords = ["web", "framework"] keywords = [
classifiers = ["Development Status :: 4 - Beta"] "web",
"framework",
]
classifiers = [
"Development Status :: 4 - Beta",
]
packages = [
{include = "reflex"}
]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = ">=3.10, <4.0" python = "^3.7"
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1" cloudpickle = "^2.2.1"
gunicorn = ">=20.1.0,<24.0" fastapi = "^0.96.0"
jinja2 = ">=3.1.2,<4.0" gunicorn = "^20.1.0"
psutil = ">=5.9.4,<7.0" httpx = "^0.24.0"
pydantic = ">=1.10.21,<3.0" jinja2 = "^3.1.2"
python-multipart = ">=0.0.5,<0.1" plotly = "^5.13.0"
python-socketio = ">=5.7.0,<6.0" psutil = "^5.9.4"
redis = ">=4.3.5,<6.0" pydantic = "^1.10.2"
rich = ">=13.0.0,<14.0" python-multipart = "^0.0.5"
sqlmodel = ">=0.0.14,<0.1" python-socketio = "^5.7.0"
typer = ">=0.15.1,<1.0" redis = "^4.3.5"
uvicorn = ">=0.20.0" rich = "^13.0.0"
starlette-admin = ">=0.11.0,<1.0" sqlmodel = "^0.0.8"
alembic = ">=1.11.1,<2.0" typer = "0.4.2"
platformdirs = ">=3.10.0,<5.0" uvicorn = "^0.20.0"
distro = { version = ">=1.8.0,<2.0", platform = "linux" } watchdog = "^2.3.1"
python-engineio = "!=4.6.0" watchfiles = "^0.19.0"
wrapt = ">=1.17.0,<2.0" websockets = "^10.4"
packaging = ">=23.1,<25.0" starlette-admin = "^0.9.0"
reflex-hosting-cli = ">=0.1.29" importlib-metadata = {version = "^6.7.0", python = ">=3.7, <3.8"}
charset-normalizer = ">=3.3.2,<4.0" alembic = "^1.11.1"
wheel = ">=0.42.0,<1.0" platformdirs = "^3.10.0"
build = ">=1.0.3,<2.0" distro = {version = "^1.8.0", platform = "linux"}
setuptools = ">=75.0"
httpx = ">=0.25.1,<1.0"
twine = ">=4.0.0,<7.0"
tomlkit = ">=0.12.4,<1.0"
lazy_loader = ">=0.4"
typing_extensions = ">=4.6.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = ">=7.1.2,<9.0" pytest = "^7.1.2"
pytest-mock = ">=3.10.0,<4.0" pytest-mock = "^3.10.0"
pyright = ">=1.1.394, <1.2" pyright = "^1.1.229"
darglint = ">=1.8.1,<2.0" darglint = "^1.8.1"
dill = ">=0.3.8" toml = "^0.10.2"
toml = ">=0.10.2,<1.0" pytest-asyncio = "^0.20.1"
pytest-asyncio = ">=0.24.0" pytest-cov = "^4.0.0"
pytest-cov = ">=4.0.0,<7.0" black = "^22.10.0"
ruff = "0.9.6" ruff = "^0.0.244"
pandas = ">=2.1.1,<3.0" pandas = [
pillow = ">=10.0.0,<12.0" {version = "^1.5.3", python = ">=3.8,<4.0"},
plotly = ">=5.13.0,<6.0" {version = "^1.1", python = ">=3.7, <3.8"}
asynctest = ">=0.13.0,<1.0" ]
pre-commit = ">=3.2.1" asynctest = "^0.13.0"
selenium = ">=4.11.0,<5.0" pre-commit = {version = "^3.2.1", python = ">=3.8,<4.0"}
pytest-benchmark = ">=4.0.0,<6.0" selenium = "^4.10.0"
playwright = ">=1.46.0"
pytest-playwright = ">=0.5.1"
pytest-codspeed = "^3.1.2"
[tool.poetry.scripts] [tool.poetry.scripts]
reflex = "reflex.reflex:cli" reflex = "reflex.reflex:cli"
@ -78,60 +74,17 @@ requires = ["poetry-core>=1.5.1"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.pyright] [tool.pyright]
reportIncompatibleMethodOverride = false
[tool.ruff] [tool.ruff]
target-version = "py310"
output-format = "concise"
lint.isort.split-on-trailing-comma = false
lint.select = [
"ANN001",
"B",
"C4",
"D",
"E",
"ERA",
"F",
"FURB",
"I",
"N",
"PERF",
"PGH",
"PTH",
"RUF",
"SIM",
"T",
"TRY",
"W",
]
lint.ignore = [
"B008",
"D205",
"E501",
"F403",
"SIM115",
"RUF006",
"RUF008",
"RUF012",
"TRY0",
]
lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores] select = ["B", "D", "E", "F", "I", "SIM", "W"]
ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
target-version = "py37"
[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"] "__init__.py" = ["F401"]
"tests/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"] "tests/*.py" = ["D100", "D103", "D104"]
"benchmarks/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
"reflex/.templates/*.py" = ["D100", "D103", "D104"] "reflex/.templates/*.py" = ["D100", "D103", "D104"]
"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N", "PGH"]
"pyi_generator.py" = ["N802"]
"reflex/constants/*.py" = ["N"]
"*/blank.py" = ["I001"]
[tool.pytest.ini_options]
filterwarnings = "ignore:fields may not start with an underscore:RuntimeWarning"
asyncio_default_fixture_loop_scope = "function"
asyncio_mode = "auto"
[tool.codespell]
skip = "docs/*,*.html,examples/*, *.pyi, poetry.lock"
ignore-words-list = "te, TreeE"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,39 +0,0 @@
"""Welcome to Reflex! This file outlines the steps to create a basic app."""
import reflex as rx
from rxconfig import config
class State(rx.State):
"""The app state."""
...
def index() -> rx.Component:
# Welcome Page (Index)
return rx.container(
rx.color_mode.button(position="top-right"),
rx.vstack(
rx.heading("Welcome to Reflex!", size="9"),
rx.text(
"Get started by editing ",
rx.code(f"{config.app_name}/{config.app_name}.py"),
size="5",
),
rx.link(
rx.button("Check out our docs!"),
href="https://reflex.dev/docs/getting-started/introduction/",
is_external=True,
),
spacing="5",
justify="center",
min_height="85vh",
),
rx.logo(),
)
app = rx.App()
app.add_page(index)

View File

@ -0,0 +1,53 @@
"""Welcome to Reflex! This file creates a counter app."""
import random
import reflex as rx
class State(rx.State):
"""The app state."""
count = 0
def increment(self):
"""Increment the count."""
self.count += 1
def decrement(self):
"""Decrement the count."""
self.count -= 1
def random(self):
"""Randomize the count."""
self.count = random.randint(0, 100)
def index() -> rx.Component:
return rx.center(
rx.vstack(
rx.heading(State.count),
rx.hstack(
rx.button("Decrement", on_click=State.decrement, color_scheme="red"),
rx.button(
"Randomize",
on_click=State.random,
background_image="linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(0,176,34,1) 100%)",
color="white",
),
rx.button("Increment", on_click=State.increment, color_scheme="green"),
),
padding="1em",
bg="#ededed",
border_radius="1em",
box_shadow="lg",
),
padding_y="5em",
font_size="2em",
text_align="center",
)
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="Counter")
app.compile()

View File

@ -0,0 +1,45 @@
"""Welcome to Reflex! This file outlines the steps to create a basic app."""
from rxconfig import config
import reflex as rx
docs_url = "https://reflex.dev/docs/getting-started/introduction"
filename = f"{config.app_name}/{config.app_name}.py"
class State(rx.State):
"""The app state."""
pass
def index() -> rx.Component:
return rx.fragment(
rx.color_mode_button(rx.color_mode_icon(), float="right"),
rx.vstack(
rx.heading("Welcome to Reflex!", font_size="2em"),
rx.box("Get started by editing ", rx.code(filename, font_size="1em")),
rx.link(
"Check out our docs!",
href=docs_url,
border="0.1em solid",
padding="0.5em",
border_radius="0.5em",
_hover={
"color": rx.color_mode_cond(
light="rgb(107,99,246)",
dark="rgb(179, 175, 255)",
)
},
),
spacing="1.5em",
font_size="2em",
padding_top="10%",
),
)
# Add state and page to the app.
app = rx.App()
app.add_page(index)
app.compile()

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,5 +1,8 @@
import reflex as rx import reflex as rx
config = rx.Config( class {{ config_name }}(rx.Config):
pass
config = {{ config_name }}(
app_name="{{ app_name }}", app_name="{{ app_name }}",
) )

View File

@ -1,9 +0,0 @@
# {{ module_name }}
A Reflex custom component {{ module_name }}.
## Installation
```bash
pip install {{ package_name }}
```

View File

@ -1 +0,0 @@
from .{{ module_name }} import *

Some files were not shown because too many files have changed in this diff Show More