Automatic Install FNM and Node for Windows: (#1566)

This commit is contained in:
Elijah Ahianyo 2023-08-17 18:23:09 +00:00 committed by GitHub
parent afcbe7e5a6
commit 98fae89319
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 228 additions and 67 deletions

108
poetry.lock generated
View File

@ -1,9 +1,10 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
[[package]] [[package]]
name = "alembic" name = "alembic"
version = "1.11.1" version = "1.11.1"
description = "A database migration tool for SQLAlchemy." description = "A database migration tool for SQLAlchemy."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -25,6 +26,7 @@ tz = ["python-dateutil"]
name = "anyio" name = "anyio"
version = "3.7.1" version = "3.7.1"
description = "High level compatibility layer for multiple asynchronous event loop implementations" description = "High level compatibility layer for multiple asynchronous event loop implementations"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -47,6 +49,7 @@ trio = ["trio (<0.22)"]
name = "async-timeout" name = "async-timeout"
version = "4.0.2" version = "4.0.2"
description = "Timeout context manager for asyncio programs" description = "Timeout context manager for asyncio programs"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -61,6 +64,7 @@ typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
name = "asynctest" name = "asynctest"
version = "0.13.0" version = "0.13.0"
description = "Enhance the standard unittest package with features for testing asyncio libraries" description = "Enhance the standard unittest package with features for testing asyncio libraries"
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -72,6 +76,7 @@ files = [
name = "attrs" name = "attrs"
version = "23.1.0" version = "23.1.0"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -93,6 +98,7 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte
name = "bidict" name = "bidict"
version = "0.22.1" version = "0.22.1"
description = "The bidirectional mapping library for Python." description = "The bidirectional mapping library for Python."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -109,6 +115,7 @@ test = ["hypothesis", "pytest", "pytest-benchmark[histogram]", "pytest-cov", "py
name = "black" name = "black"
version = "22.12.0" version = "22.12.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -145,6 +152,7 @@ uvloop = ["uvloop (>=0.15.2)"]
name = "certifi" name = "certifi"
version = "2023.7.22" version = "2023.7.22"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -156,6 +164,7 @@ files = [
name = "cffi" name = "cffi"
version = "1.15.1" version = "1.15.1"
description = "Foreign Function Interface for Python calling C code." description = "Foreign Function Interface for Python calling C code."
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -232,6 +241,7 @@ pycparser = "*"
name = "cfgv" name = "cfgv"
version = "3.3.1" version = "3.3.1"
description = "Validate configuration and produce human readable error messages." description = "Validate configuration and produce human readable error messages."
category = "dev"
optional = false optional = false
python-versions = ">=3.6.1" python-versions = ">=3.6.1"
files = [ files = [
@ -243,6 +253,7 @@ files = [
name = "click" name = "click"
version = "8.1.6" version = "8.1.6"
description = "Composable command line interface toolkit" description = "Composable command line interface toolkit"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -258,6 +269,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
name = "cloudpickle" name = "cloudpickle"
version = "2.2.1" version = "2.2.1"
description = "Extended pickling support for Python objects" description = "Extended pickling support for Python objects"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -269,6 +281,7 @@ files = [
name = "colorama" name = "colorama"
version = "0.4.6" version = "0.4.6"
description = "Cross-platform colored terminal text." description = "Cross-platform colored terminal text."
category = "main"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [ files = [
@ -280,6 +293,7 @@ files = [
name = "coverage" name = "coverage"
version = "7.2.7" version = "7.2.7"
description = "Code coverage measurement for Python" description = "Code coverage measurement for Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -355,6 +369,7 @@ toml = ["tomli"]
name = "darglint" name = "darglint"
version = "1.8.1" version = "1.8.1"
description = "A utility for ensuring Google-style docstrings stay up to date with the source code." description = "A utility for ensuring Google-style docstrings stay up to date with the source code."
category = "dev"
optional = false optional = false
python-versions = ">=3.6,<4.0" python-versions = ">=3.6,<4.0"
files = [ files = [
@ -366,6 +381,7 @@ files = [
name = "distlib" name = "distlib"
version = "0.3.7" version = "0.3.7"
description = "Distribution utilities" description = "Distribution utilities"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -377,6 +393,7 @@ files = [
name = "exceptiongroup" name = "exceptiongroup"
version = "1.1.2" version = "1.1.2"
description = "Backport of PEP 654 (exception groups)" description = "Backport of PEP 654 (exception groups)"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -391,6 +408,7 @@ test = ["pytest (>=6)"]
name = "fastapi" name = "fastapi"
version = "0.96.1" version = "0.96.1"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -412,6 +430,7 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6
name = "filelock" name = "filelock"
version = "3.12.2" version = "3.12.2"
description = "A platform independent file lock." description = "A platform independent file lock."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -427,6 +446,7 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p
name = "greenlet" name = "greenlet"
version = "2.0.2" version = "2.0.2"
description = "Lightweight in-process concurrent programming" description = "Lightweight in-process concurrent programming"
category = "main"
optional = false optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
files = [ files = [
@ -500,6 +520,7 @@ test = ["objgraph", "psutil"]
name = "gunicorn" name = "gunicorn"
version = "20.1.0" version = "20.1.0"
description = "WSGI HTTP Server for UNIX" description = "WSGI HTTP Server for UNIX"
category = "main"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -520,6 +541,7 @@ tornado = ["tornado (>=0.2)"]
name = "h11" name = "h11"
version = "0.14.0" version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -534,6 +556,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
name = "httpcore" name = "httpcore"
version = "0.17.3" version = "0.17.3"
description = "A minimal low-level HTTP client." description = "A minimal low-level HTTP client."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -545,16 +568,17 @@ files = [
anyio = ">=3.0,<5.0" anyio = ">=3.0,<5.0"
certifi = "*" certifi = "*"
h11 = ">=0.13,<0.15" h11 = ">=0.13,<0.15"
sniffio = "==1.*" sniffio = ">=1.0.0,<2.0.0"
[package.extras] [package.extras]
http2 = ["h2 (>=3,<5)"] http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"] socks = ["socksio (>=1.0.0,<2.0.0)"]
[[package]] [[package]]
name = "httpx" name = "httpx"
version = "0.24.1" version = "0.24.1"
description = "The next generation HTTP client." description = "The next generation HTTP client."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -570,14 +594,15 @@ sniffio = "*"
[package.extras] [package.extras]
brotli = ["brotli", "brotlicffi"] brotli = ["brotli", "brotlicffi"]
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"]
http2 = ["h2 (>=3,<5)"] http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"] socks = ["socksio (>=1.0.0,<2.0.0)"]
[[package]] [[package]]
name = "identify" name = "identify"
version = "2.5.26" version = "2.5.26"
description = "File identification library for Python" description = "File identification library for Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -592,6 +617,7 @@ license = ["ukkonen"]
name = "idna" name = "idna"
version = "3.4" version = "3.4"
description = "Internationalized Domain Names in Applications (IDNA)" description = "Internationalized Domain Names in Applications (IDNA)"
category = "main"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -603,6 +629,7 @@ files = [
name = "importlib-metadata" name = "importlib-metadata"
version = "6.7.0" version = "6.7.0"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -623,6 +650,7 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs
name = "importlib-resources" name = "importlib-resources"
version = "5.12.0" version = "5.12.0"
description = "Read resources from Python packages" description = "Read resources from Python packages"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -641,6 +669,7 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec
name = "iniconfig" name = "iniconfig"
version = "2.0.0" version = "2.0.0"
description = "brain-dead simple config-ini parsing" description = "brain-dead simple config-ini parsing"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -652,6 +681,7 @@ files = [
name = "jinja2" name = "jinja2"
version = "3.1.2" version = "3.1.2"
description = "A very fast and expressive template engine." description = "A very fast and expressive template engine."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -669,6 +699,7 @@ i18n = ["Babel (>=2.7)"]
name = "mako" name = "mako"
version = "1.2.4" version = "1.2.4"
description = "A super-fast templating language that borrows the best ideas from the existing templating languages." description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -689,6 +720,7 @@ testing = ["pytest"]
name = "markdown-it-py" name = "markdown-it-py"
version = "2.2.0" version = "2.2.0"
description = "Python port of markdown-it. Markdown parsing, done right!" description = "Python port of markdown-it. Markdown parsing, done right!"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -714,6 +746,7 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
name = "markupsafe" name = "markupsafe"
version = "2.1.3" version = "2.1.3"
description = "Safely add untrusted strings to HTML/XML markup." description = "Safely add untrusted strings to HTML/XML markup."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -773,6 +806,7 @@ files = [
name = "mdurl" name = "mdurl"
version = "0.1.2" version = "0.1.2"
description = "Markdown URL utilities" description = "Markdown URL utilities"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -784,6 +818,7 @@ files = [
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker." description = "Type system extensions for programs checked with the mypy type checker."
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
files = [ files = [
@ -795,6 +830,7 @@ files = [
name = "nodeenv" name = "nodeenv"
version = "1.8.0" version = "1.8.0"
description = "Node.js virtual environment builder" description = "Node.js virtual environment builder"
category = "dev"
optional = false optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
files = [ files = [
@ -809,6 +845,7 @@ setuptools = "*"
name = "numpy" name = "numpy"
version = "1.21.6" version = "1.21.6"
description = "NumPy is the fundamental package for array computing with Python." description = "NumPy is the fundamental package for array computing with Python."
category = "dev"
optional = false optional = false
python-versions = ">=3.7,<3.11" python-versions = ">=3.7,<3.11"
files = [ files = [
@ -849,6 +886,7 @@ files = [
name = "numpy" name = "numpy"
version = "1.24.4" version = "1.24.4"
description = "Fundamental package for array computing in Python" description = "Fundamental package for array computing in Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -886,6 +924,7 @@ files = [
name = "numpy" name = "numpy"
version = "1.25.2" version = "1.25.2"
description = "Fundamental package for array computing in Python" description = "Fundamental package for array computing in Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
@ -920,6 +959,7 @@ files = [
name = "outcome" name = "outcome"
version = "1.2.0" version = "1.2.0"
description = "Capture the outcome of Python function calls." description = "Capture the outcome of Python function calls."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -934,6 +974,7 @@ attrs = ">=19.2.0"
name = "packaging" name = "packaging"
version = "23.1" version = "23.1"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -945,6 +986,7 @@ files = [
name = "pandas" name = "pandas"
version = "1.1.5" version = "1.1.5"
description = "Powerful data structures for data analysis, time series, and statistics" description = "Powerful data structures for data analysis, time series, and statistics"
category = "dev"
optional = false optional = false
python-versions = ">=3.6.1" python-versions = ">=3.6.1"
files = [ files = [
@ -986,6 +1028,7 @@ test = ["hypothesis (>=3.58)", "pytest (>=4.0.2)", "pytest-xdist"]
name = "pandas" name = "pandas"
version = "1.5.3" version = "1.5.3"
description = "Powerful data structures for data analysis, time series, and statistics" description = "Powerful data structures for data analysis, time series, and statistics"
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -1034,6 +1077,7 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"]
name = "pathspec" name = "pathspec"
version = "0.11.2" version = "0.11.2"
description = "Utility library for gitignore style pattern matching of file paths." description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1045,6 +1089,7 @@ files = [
name = "platformdirs" name = "platformdirs"
version = "3.10.0" version = "3.10.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1063,6 +1108,7 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
name = "plotly" name = "plotly"
version = "5.15.0" version = "5.15.0"
description = "An open-source, interactive data visualization library for Python" description = "An open-source, interactive data visualization library for Python"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1078,6 +1124,7 @@ tenacity = ">=6.2.0"
name = "pluggy" name = "pluggy"
version = "1.2.0" version = "1.2.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1096,6 +1143,7 @@ testing = ["pytest", "pytest-benchmark"]
name = "pre-commit" name = "pre-commit"
version = "3.3.3" version = "3.3.3"
description = "A framework for managing and maintaining multi-language pre-commit hooks." description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -1114,6 +1162,7 @@ virtualenv = ">=20.10.0"
name = "psutil" name = "psutil"
version = "5.9.5" version = "5.9.5"
description = "Cross-platform lib for process and system monitoring in Python." description = "Cross-platform lib for process and system monitoring in Python."
category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [ files = [
@ -1140,6 +1189,7 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
name = "pycparser" name = "pycparser"
version = "2.21" version = "2.21"
description = "C parser in Python" description = "C parser in Python"
category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [ files = [
@ -1151,6 +1201,7 @@ files = [
name = "pydantic" name = "pydantic"
version = "1.10.12" version = "1.10.12"
description = "Data validation and settings management using python type hints" description = "Data validation and settings management using python type hints"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1203,6 +1254,7 @@ email = ["email-validator (>=1.0.3)"]
name = "pygments" name = "pygments"
version = "2.15.1" version = "2.15.1"
description = "Pygments is a syntax highlighting package written in Python." description = "Pygments is a syntax highlighting package written in Python."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1217,6 +1269,7 @@ plugins = ["importlib-metadata"]
name = "pyright" name = "pyright"
version = "1.1.318" version = "1.1.318"
description = "Command line wrapper for pyright" description = "Command line wrapper for pyright"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1236,6 +1289,7 @@ dev = ["twine (>=3.4.1)"]
name = "pysocks" name = "pysocks"
version = "1.7.1" version = "1.7.1"
description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [ files = [
@ -1248,6 +1302,7 @@ files = [
name = "pytest" name = "pytest"
version = "7.4.0" version = "7.4.0"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1271,6 +1326,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no
name = "pytest-asyncio" name = "pytest-asyncio"
version = "0.20.3" version = "0.20.3"
description = "Pytest support for asyncio" description = "Pytest support for asyncio"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1290,6 +1346,7 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy
name = "pytest-cov" name = "pytest-cov"
version = "4.1.0" version = "4.1.0"
description = "Pytest plugin for measuring coverage." description = "Pytest plugin for measuring coverage."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1308,6 +1365,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale
name = "pytest-mock" name = "pytest-mock"
version = "3.11.1" version = "3.11.1"
description = "Thin-wrapper around the mock package for easier use with pytest" description = "Thin-wrapper around the mock package for easier use with pytest"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1325,6 +1383,7 @@ dev = ["pre-commit", "pytest-asyncio", "tox"]
name = "python-dateutil" name = "python-dateutil"
version = "2.8.2" version = "2.8.2"
description = "Extensions to the standard Python datetime module" description = "Extensions to the standard Python datetime module"
category = "dev"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [ files = [
@ -1339,6 +1398,7 @@ six = ">=1.5"
name = "python-dotenv" name = "python-dotenv"
version = "0.13.0" version = "0.13.0"
description = "Add .env support to your django/flask apps in development and deployments" description = "Add .env support to your django/flask apps in development and deployments"
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -1353,6 +1413,7 @@ cli = ["click (>=5.0)"]
name = "python-engineio" name = "python-engineio"
version = "4.5.1" version = "4.5.1"
description = "Engine.IO server and client for Python" description = "Engine.IO server and client for Python"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1369,6 +1430,7 @@ docs = ["sphinx"]
name = "python-multipart" name = "python-multipart"
version = "0.0.5" version = "0.0.5"
description = "A streaming multipart parser for Python" description = "A streaming multipart parser for Python"
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -1382,6 +1444,7 @@ six = ">=1.4.0"
name = "python-socketio" name = "python-socketio"
version = "5.8.0" version = "5.8.0"
description = "Socket.IO server and client for Python" description = "Socket.IO server and client for Python"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1401,6 +1464,7 @@ client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
name = "pytz" name = "pytz"
version = "2023.3" version = "2023.3"
description = "World timezone definitions, modern and historical" description = "World timezone definitions, modern and historical"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -1412,6 +1476,7 @@ files = [
name = "pyyaml" name = "pyyaml"
version = "6.0.1" version = "6.0.1"
description = "YAML parser and emitter for Python" description = "YAML parser and emitter for Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1461,6 +1526,7 @@ files = [
name = "redis" name = "redis"
version = "4.6.0" version = "4.6.0"
description = "Python client for Redis database and key-value store" description = "Python client for Redis database and key-value store"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1481,6 +1547,7 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
name = "rich" name = "rich"
version = "13.5.1" version = "13.5.1"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
category = "main"
optional = false optional = false
python-versions = ">=3.7.0" python-versions = ">=3.7.0"
files = [ files = [
@ -1500,6 +1567,7 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
name = "ruff" name = "ruff"
version = "0.0.244" version = "0.0.244"
description = "An extremely fast Python linter, written in Rust." description = "An extremely fast Python linter, written in Rust."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1525,6 +1593,7 @@ files = [
name = "selenium" name = "selenium"
version = "4.10.0" version = "4.10.0"
description = "" description = ""
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1542,6 +1611,7 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]}
name = "setuptools" name = "setuptools"
version = "68.0.0" version = "68.0.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages" description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1558,6 +1628,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
name = "six" name = "six"
version = "1.16.0" version = "1.16.0"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [ files = [
@ -1569,6 +1640,7 @@ files = [
name = "sniffio" name = "sniffio"
version = "1.3.0" version = "1.3.0"
description = "Sniff out which async library your code is running under" description = "Sniff out which async library your code is running under"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1580,6 +1652,7 @@ files = [
name = "sortedcontainers" name = "sortedcontainers"
version = "2.4.0" version = "2.4.0"
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
@ -1591,6 +1664,7 @@ files = [
name = "sqlalchemy" name = "sqlalchemy"
version = "1.4.41" version = "1.4.41"
description = "Database Abstraction Library" description = "Database Abstraction Library"
category = "main"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [ files = [
@ -1638,7 +1712,7 @@ files = [
] ]
[package.dependencies] [package.dependencies]
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""}
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
@ -1666,6 +1740,7 @@ sqlcipher = ["sqlcipher3-binary"]
name = "sqlalchemy2-stubs" name = "sqlalchemy2-stubs"
version = "0.0.2a35" version = "0.0.2a35"
description = "Typing Stubs for SQLAlchemy 1.4" description = "Typing Stubs for SQLAlchemy 1.4"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1680,6 +1755,7 @@ typing-extensions = ">=3.7.4"
name = "sqlmodel" name = "sqlmodel"
version = "0.0.8" version = "0.0.8"
description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness."
category = "main"
optional = false optional = false
python-versions = ">=3.6.1,<4.0.0" python-versions = ">=3.6.1,<4.0.0"
files = [ files = [
@ -1696,6 +1772,7 @@ sqlalchemy2-stubs = "*"
name = "starlette" name = "starlette"
version = "0.27.0" version = "0.27.0"
description = "The little ASGI library that shines." description = "The little ASGI library that shines."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1714,6 +1791,7 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam
name = "starlette-admin" name = "starlette-admin"
version = "0.9.0" version = "0.9.0"
description = "Fast, beautiful and extensible administrative interface framework for Starlette/FastApi applications" description = "Fast, beautiful and extensible administrative interface framework for Starlette/FastApi applications"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1736,6 +1814,7 @@ test = ["aiomysql (>=0.1.1,<0.2.0)", "aiosqlite (>=0.17.0,<0.20.0)", "arrow (>=1
name = "tenacity" name = "tenacity"
version = "8.2.2" version = "8.2.2"
description = "Retry code until it succeeds" description = "Retry code until it succeeds"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1750,6 +1829,7 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"]
name = "toml" name = "toml"
version = "0.10.2" version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language" description = "Python Library for Tom's Obvious, Minimal Language"
category = "dev"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
files = [ files = [
@ -1761,6 +1841,7 @@ files = [
name = "tomli" name = "tomli"
version = "2.0.1" version = "2.0.1"
description = "A lil' TOML parser" description = "A lil' TOML parser"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1772,6 +1853,7 @@ files = [
name = "trio" name = "trio"
version = "0.22.2" version = "0.22.2"
description = "A friendly Python library for async concurrency and I/O" description = "A friendly Python library for async concurrency and I/O"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1792,6 +1874,7 @@ sortedcontainers = "*"
name = "trio-websocket" name = "trio-websocket"
version = "0.10.3" version = "0.10.3"
description = "WebSocket library for Trio" description = "WebSocket library for Trio"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1808,6 +1891,7 @@ wsproto = ">=0.14"
name = "typed-ast" name = "typed-ast"
version = "1.5.5" version = "1.5.5"
description = "a fork of Python 2 and 3 ast modules with type comment support" description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1858,6 +1942,7 @@ files = [
name = "typer" name = "typer"
version = "0.4.2" version = "0.4.2"
description = "Typer, build great CLIs. Easy to code. Based on Python type hints." description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1878,6 +1963,7 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=5.2,<6.0)", "isort (>=5.0.6,<6.
name = "typing-extensions" name = "typing-extensions"
version = "4.7.1" version = "4.7.1"
description = "Backported and Experimental Type Hints for Python 3.7+" description = "Backported and Experimental Type Hints for Python 3.7+"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1889,6 +1975,7 @@ files = [
name = "urllib3" name = "urllib3"
version = "2.0.4" version = "2.0.4"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1909,6 +1996,7 @@ zstd = ["zstandard (>=0.18.0)"]
name = "uvicorn" name = "uvicorn"
version = "0.20.0" version = "0.20.0"
description = "The lightning-fast ASGI server." description = "The lightning-fast ASGI server."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1928,6 +2016,7 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
name = "virtualenv" name = "virtualenv"
version = "20.24.2" version = "20.24.2"
description = "Virtual Python Environment builder" description = "Virtual Python Environment builder"
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1948,6 +2037,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
name = "watchdog" name = "watchdog"
version = "2.3.1" version = "2.3.1"
description = "Filesystem events monitoring" description = "Filesystem events monitoring"
category = "main"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
@ -1988,6 +2078,7 @@ watchmedo = ["PyYAML (>=3.10)"]
name = "watchfiles" name = "watchfiles"
version = "0.19.0" version = "0.19.0"
description = "Simple, modern and high performance file watching and code reload in python." description = "Simple, modern and high performance file watching and code reload in python."
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -2022,6 +2113,7 @@ anyio = ">=3.0.0"
name = "websockets" name = "websockets"
version = "10.4" version = "10.4"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -2100,6 +2192,7 @@ files = [
name = "wsproto" name = "wsproto"
version = "1.2.0" version = "1.2.0"
description = "WebSockets state-machine based protocol implementation" description = "WebSockets state-machine based protocol implementation"
category = "dev"
optional = false optional = false
python-versions = ">=3.7.0" python-versions = ">=3.7.0"
files = [ files = [
@ -2114,6 +2207,7 @@ h11 = ">=0.9.0,<1"
name = "zipp" name = "zipp"
version = "3.15.0" version = "3.15.0"
description = "Backport of pathlib-compatible object wrapper for zip files" description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -2128,4 +2222,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "ac27016107e8a033aa39d9a712d3ef685132e22ede599a26214b17da6ff35829" content-hash = "ba03a445b7e59587264636a98b52595e020ae58570ac79b0fb1b9564c9769c59"

View File

@ -46,6 +46,7 @@ starlette-admin = "^0.9.0"
python-dotenv = "^0.13.0" python-dotenv = "^0.13.0"
importlib-metadata = {version = "^6.7.0", python = ">=3.7, <3.8"} importlib-metadata = {version = "^6.7.0", python = ">=3.7, <3.8"}
alembic = "^1.11.1" alembic = "^1.11.1"
platformdirs = "^3.10.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = "^7.1.2" pytest = "^7.1.2"

View File

@ -8,12 +8,16 @@ from enum import Enum
from types import SimpleNamespace from types import SimpleNamespace
from typing import Any, Type from typing import Any, Type
from platformdirs import PlatformDirs
# importlib is only available for Python 3.8+ so we need the backport for Python 3.7 # importlib is only available for Python 3.8+ so we need the backport for Python 3.7
try: try:
from importlib import metadata from importlib import metadata
except ImportError: except ImportError:
import importlib_metadata as metadata # pyright: ignore[reportMissingImports] import importlib_metadata as metadata # pyright: ignore[reportMissingImports]
IS_WINDOWS = platform.system() == "Windows"
def get_value(key: str, default: Any = None, type_: Type = str) -> Type: def get_value(key: str, default: Any = None, type_: Type = str) -> Type:
"""Get the value for the constant. """Get the value for the constant.
@ -48,7 +52,17 @@ VERSION = metadata.version(MODULE_NAME)
# Files and directories used to init a new project. # Files and directories used to init a new project.
# The directory to store reflex dependencies. # The directory to store reflex dependencies.
REFLEX_DIR = os.path.expandvars(os.path.join("$HOME", f".{MODULE_NAME}")) REFLEX_DIR = (
# on windows, we use C:/Users/<username>/AppData/Local/reflex.
PlatformDirs(MODULE_NAME, False).user_data_dir
if IS_WINDOWS
else os.path.expandvars(
os.path.join(
"$HOME",
f".{MODULE_NAME}",
),
)
)
# The root directory of the reflex library. # The root directory of the reflex library.
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# The name of the assets directory. # The name of the assets directory.
@ -79,29 +93,38 @@ BUN_INSTALL_URL = "https://bun.sh/install"
# NVM / Node config. # NVM / Node config.
# The NVM version. # The NVM version.
NVM_VERSION = "0.39.1" NVM_VERSION = "0.39.1"
# The FNM version.
FNM_VERSION = "1.35.1"
# The Node version. # The Node version.
NODE_VERSION = "18.17.0" NODE_VERSION = "18.17.0"
# The minimum required node version. # The minimum required node version.
NODE_VERSION_MIN = "16.8.0" NODE_VERSION_MIN = "16.8.0"
# The directory to store nvm. # The directory to store nvm.
NVM_DIR = os.path.join(REFLEX_DIR, ".nvm") NVM_DIR = os.path.join(REFLEX_DIR, ".nvm")
# The directory to store fnm.
FNM_DIR = os.path.join(REFLEX_DIR, "fnm")
# The fnm executable binary.
FNM_EXE = os.path.join(FNM_DIR, "fnm.exe")
# The nvm path. # The nvm path.
NVM_PATH = os.path.join(NVM_DIR, "nvm.sh") NVM_PATH = os.path.join(NVM_DIR, "nvm.sh")
# The node bin path. # The node bin path.
NODE_BIN_PATH = os.path.join(NVM_DIR, "versions", "node", f"v{NODE_VERSION}", "bin") NODE_BIN_PATH = (
os.path.join(NVM_DIR, "versions", "node", f"v{NODE_VERSION}", "bin")
if not IS_WINDOWS
else os.path.join(FNM_DIR, "node-versions", f"v{NODE_VERSION}", "installation")
)
# The default path where node is installed. # The default path where node is installed.
NODE_PATH = ( NODE_PATH = os.path.join(NODE_BIN_PATH, "node.exe" if IS_WINDOWS else "node")
"node" if platform.system() == "Windows" else os.path.join(NODE_BIN_PATH, "node")
)
# The default path where npm is installed. # The default path where npm is installed.
NPM_PATH = ( NPM_PATH = os.path.join(NODE_BIN_PATH, "npm")
"npm" if platform.system() == "Windows" else os.path.join(NODE_BIN_PATH, "npm")
)
# The URL to the nvm install script. # The URL to the nvm install script.
NVM_INSTALL_URL = ( NVM_INSTALL_URL = (
f"https://raw.githubusercontent.com/nvm-sh/nvm/v{NVM_VERSION}/install.sh" f"https://raw.githubusercontent.com/nvm-sh/nvm/v{NVM_VERSION}/install.sh"
) )
# The URL to the fnm release binary
FNM_WINDOWS_INSTALL_URL = (
f"https://github.com/Schniz/fnm/releases/download/v{FNM_VERSION}/fnm-windows.zip"
)
# The frontend directories in a project. # The frontend directories in a project.
# The web folder where the NextJS app is compiled to. # The web folder where the NextJS app is compiled to.
WEB_DIR = ".web" WEB_DIR = ".web"

View File

@ -124,6 +124,7 @@ def export(
process = processes.new_process( process = processes.new_process(
[prerequisites.get_package_manager(), "run", command], [prerequisites.get_package_manager(), "run", command],
cwd=constants.WEB_DIR, cwd=constants.WEB_DIR,
shell=constants.IS_WINDOWS,
) )
processes.show_progress("Creating Production Build", process, checkpoints) processes.show_progress("Creating Production Build", process, checkpoints)
@ -201,6 +202,7 @@ def setup_frontend(
], ],
cwd=constants.WEB_DIR, cwd=constants.WEB_DIR,
stdout=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
shell=constants.IS_WINDOWS,
) )

View File

@ -30,8 +30,7 @@ def run_process_and_launch_url(
run_command: The command to run. run_command: The command to run.
""" """
process = processes.new_process( process = processes.new_process(
run_command, run_command, cwd=constants.WEB_DIR, shell=constants.IS_WINDOWS
cwd=constants.WEB_DIR,
) )
if process.stdout: if process.stdout:
@ -137,7 +136,7 @@ def run_backend_prod(
str(port), str(port),
f"{app_name}:{constants.APP_VAR}", f"{app_name}:{constants.APP_VAR}",
] ]
if prerequisites.IS_WINDOWS if constants.IS_WINDOWS
else [ else [
*constants.RUN_BACKEND_PROD, *constants.RUN_BACKEND_PROD,
"--bind", "--bind",

View File

@ -5,10 +5,10 @@ from __future__ import annotations
import glob import glob
import json import json
import os import os
import platform
import re import re
import sys import sys
import tempfile import tempfile
import zipfile
from fileinput import FileInput from fileinput import FileInput
from pathlib import Path from pathlib import Path
from types import ModuleType from types import ModuleType
@ -24,8 +24,6 @@ from reflex import constants, model
from reflex.config import get_config from reflex.config import get_config
from reflex.utils import console, path_ops, processes from reflex.utils import console, path_ops, processes
IS_WINDOWS = platform.system() == "Windows"
def check_node_version() -> bool: def check_node_version() -> bool:
"""Check the version of Node.js. """Check the version of Node.js.
@ -44,7 +42,7 @@ def check_node_version() -> bool:
# Compare the version numbers # Compare the version numbers
return ( return (
current_version >= version.parse(constants.NODE_VERSION_MIN) current_version >= version.parse(constants.NODE_VERSION_MIN)
if IS_WINDOWS if constants.IS_WINDOWS
else current_version == version.parse(constants.NODE_VERSION) else current_version == version.parse(constants.NODE_VERSION)
) )
@ -85,11 +83,9 @@ def get_install_package_manager() -> str:
Returns: Returns:
The path to the package manager. The path to the package manager.
""" """
get_config()
# On Windows, we use npm instead of bun. # On Windows, we use npm instead of bun.
if IS_WINDOWS: if constants.IS_WINDOWS:
return get_windows_package_manager() return constants.NPM_PATH
# On other platforms, we use bun. # On other platforms, we use bun.
return get_config().bun_path return get_config().bun_path
@ -102,10 +98,6 @@ def get_package_manager() -> str:
Returns: Returns:
The path to the package manager. The path to the package manager.
""" """
get_config()
if IS_WINDOWS:
return get_windows_package_manager()
return constants.NPM_PATH return constants.NPM_PATH
@ -279,24 +271,59 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
show(f"Installing {url}", process) show(f"Installing {url}", process)
def install_node(): def download_and_extract_fnm_zip(url: str):
"""Install nvm and nodejs for use by Reflex. """Download and run a script.
Independent of any existing system installations.
Args:
url: The url of the fnm release zip binary.
Raises: Raises:
Exit: if installation failed Exit: If an error occurs while downloading or extracting the FNM zip.
""" """
if IS_WINDOWS: # TODO: make this OS agnostic
# See if existing node is good enough. # Download the zip file
# On Windows, this must be installed manually, outside of Reflex. console.debug(f"Downloading {url}")
if not check_node_version(): fnm_zip_file = f"{constants.FNM_DIR}\\fnm_windows.zip"
# We don't currently support auto install of node on Windows # Function to download and extract the FNM zip release
# because NVM is not supported there try:
console.error( # Download the FNM zip release
f"Node.js version {constants.NODE_VERSION} or higher is required to run Reflex." # TODO: show progress to improve UX
) with httpx.stream("GET", url, follow_redirects=True) as response:
raise typer.Exit(1) response.raise_for_status()
return with open(fnm_zip_file, "wb") as output_file:
for chunk in response.iter_bytes():
output_file.write(chunk)
# Extract the downloaded zip file
with zipfile.ZipFile(fnm_zip_file, "r") as zip_ref:
zip_ref.extractall(constants.FNM_DIR)
console.debug("FNM for Windows downloaded and extracted successfully.")
except Exception as e:
console.error(f"An error occurred while downloading fnm package: {e}")
raise typer.Exit(1) from e
finally:
# Clean up the downloaded zip file
path_ops.rm(fnm_zip_file)
def install_node():
"""Install nvm and nodejs for use by Reflex.
Independent of any existing system installations.
"""
if constants.IS_WINDOWS:
path_ops.mkdir(constants.FNM_DIR)
if not os.path.exists(constants.FNM_EXE):
download_and_extract_fnm_zip(constants.FNM_WINDOWS_INSTALL_URL)
# Install node.
process = processes.new_process(
[
"powershell",
"-Command",
f'& "{constants.FNM_EXE}" install {constants.NODE_VERSION} --fnm-dir "{constants.FNM_DIR}"',
],
)
else: # All other platforms (Linux, MacOS) else: # All other platforms (Linux, MacOS)
# TODO we can skip installation if check_node_version() checks out # TODO we can skip installation if check_node_version() checks out
# Create the nvm directory and install. # Create the nvm directory and install.
@ -314,7 +341,7 @@ def install_node():
], ],
env=env, env=env,
) )
processes.show_status("Installing node", process) processes.show_status("Installing node", process)
def install_bun(): def install_bun():
@ -324,7 +351,7 @@ def install_bun():
FileNotFoundError: If required packages are not found. FileNotFoundError: If required packages are not found.
""" """
# Bun is not supported on Windows. # Bun is not supported on Windows.
if IS_WINDOWS: if constants.IS_WINDOWS:
console.debug("Skipping bun installation on Windows.") console.debug("Skipping bun installation on Windows.")
return return
@ -352,6 +379,7 @@ def install_frontend_packages():
process = processes.new_process( process = processes.new_process(
[get_install_package_manager(), "install", "--loglevel", "silly"], [get_install_package_manager(), "install", "--loglevel", "silly"],
cwd=constants.WEB_DIR, cwd=constants.WEB_DIR,
shell=constants.IS_WINDOWS,
) )
processes.show_status("Installing base frontend packages", process) processes.show_status("Installing base frontend packages", process)
@ -361,6 +389,7 @@ def install_frontend_packages():
process = processes.new_process( process = processes.new_process(
[get_install_package_manager(), "add", *packages], [get_install_package_manager(), "add", *packages],
cwd=constants.WEB_DIR, cwd=constants.WEB_DIR,
shell=constants.IS_WINDOWS,
) )
processes.show_status("Installing custom frontend packages", process) processes.show_status("Installing custom frontend packages", process)
@ -375,7 +404,7 @@ def check_initialized(frontend: bool = True):
Exit: If the app is not initialized. Exit: If the app is not initialized.
""" """
has_config = os.path.exists(constants.CONFIG_FILE) has_config = os.path.exists(constants.CONFIG_FILE)
has_reflex_dir = not frontend or IS_WINDOWS or os.path.exists(constants.REFLEX_DIR) has_reflex_dir = not frontend or os.path.exists(constants.REFLEX_DIR)
has_web_dir = not frontend or os.path.exists(constants.WEB_DIR) has_web_dir = not frontend or os.path.exists(constants.WEB_DIR)
# Check if the app is initialized. # Check if the app is initialized.
@ -393,7 +422,7 @@ def check_initialized(frontend: bool = True):
raise typer.Exit(1) raise typer.Exit(1)
# Print a warning for Windows users. # Print a warning for Windows users.
if IS_WINDOWS: if constants.IS_WINDOWS:
console.warn( console.warn(
"""Windows Subsystem for Linux (WSL) is recommended for improving initial install times.""" """Windows Subsystem for Linux (WSL) is recommended for improving initial install times."""
) )
@ -440,7 +469,7 @@ def validate_bun():
def validate_frontend_dependencies(): def validate_frontend_dependencies():
"""Validate frontend dependencies to ensure they meet requirements.""" """Validate frontend dependencies to ensure they meet requirements."""
if IS_WINDOWS: if constants.IS_WINDOWS:
return return
return validate_bun() return validate_bun()
@ -448,8 +477,7 @@ def validate_frontend_dependencies():
def initialize_frontend_dependencies(): def initialize_frontend_dependencies():
"""Initialize all the frontend dependencies.""" """Initialize all the frontend dependencies."""
# Create the reflex directory. # Create the reflex directory.
if not IS_WINDOWS: path_ops.mkdir(constants.REFLEX_DIR)
path_ops.mkdir(constants.REFLEX_DIR)
# validate dependencies before install # validate dependencies before install
validate_frontend_dependencies() validate_frontend_dependencies()
# Install the frontend dependencies. # Install the frontend dependencies.

View File

@ -1,6 +1,6 @@
"""Unit tests for the included testing tools.""" """Unit tests for the included testing tools."""
from reflex.constants import IS_WINDOWS
from reflex.testing import AppHarness from reflex.testing import AppHarness
from reflex.utils.prerequisites import IS_WINDOWS
def test_app_harness(tmp_path): def test_app_harness(tmp_path):

View File

@ -513,24 +513,42 @@ def test_app_default_name(tmp_path, mocker):
prerequisites.get_default_app_name() prerequisites.get_default_app_name()
def test_node_install_windows(mocker): def test_node_install_windows(tmp_path, mocker):
"""Require user to install node manually for windows if node is not installed. """Require user to install node manually for windows if node is not installed.
Args: Args:
tmp_path: Test working dir.
mocker: Pytest mocker object. mocker: Pytest mocker object.
""" """
mocker.patch("reflex.utils.prerequisites.IS_WINDOWS", True) fnm_root_path = tmp_path / "reflex" / "fnm"
mocker.patch("reflex.utils.prerequisites.check_node_version", return_value=False) fnm_exe = fnm_root_path / "fnm.exe"
with pytest.raises(typer.Exit): mocker.patch("reflex.utils.prerequisites.constants.FNM_DIR", fnm_root_path)
prerequisites.install_node() mocker.patch("reflex.utils.prerequisites.constants.FNM_EXE", fnm_exe)
mocker.patch("reflex.utils.prerequisites.constants.IS_WINDOWS", True)
mocker.patch("reflex.utils.processes.new_process")
mocker.patch("reflex.utils.processes.stream_logs")
class Resp(Base):
status_code = 200
text = "test"
mocker.patch("httpx.stream", return_value=Resp())
download = mocker.patch("reflex.utils.prerequisites.download_and_extract_fnm_zip")
mocker.patch("reflex.utils.prerequisites.zipfile.ZipFile")
mocker.patch("reflex.utils.prerequisites.path_ops.rm")
prerequisites.install_node()
assert fnm_root_path.exists()
download.assert_called_once()
def test_node_install_unix(tmp_path, mocker): def test_node_install_unix(tmp_path, mocker):
nvm_root_path = tmp_path / ".reflex" / ".nvm" nvm_root_path = tmp_path / ".reflex" / ".nvm"
mocker.patch("reflex.utils.prerequisites.constants.NVM_DIR", nvm_root_path) mocker.patch("reflex.utils.prerequisites.constants.NVM_DIR", nvm_root_path)
mocker.patch("reflex.utils.prerequisites.IS_WINDOWS", False) mocker.patch("reflex.utils.prerequisites.constants.IS_WINDOWS", False)
class Resp(Base): class Resp(Base):
status_code = 200 status_code = 200
@ -556,13 +574,12 @@ def test_bun_install_without_unzip(mocker):
""" """
mocker.patch("reflex.utils.path_ops.which", return_value=None) mocker.patch("reflex.utils.path_ops.which", return_value=None)
mocker.patch("os.path.exists", return_value=False) mocker.patch("os.path.exists", return_value=False)
mocker.patch("reflex.utils.prerequisites.IS_WINDOWS", False) mocker.patch("reflex.utils.prerequisites.constants.IS_WINDOWS", False)
with pytest.raises(FileNotFoundError): with pytest.raises(FileNotFoundError):
prerequisites.install_bun() prerequisites.install_bun()
# from
@pytest.mark.parametrize("is_windows", [True, False]) @pytest.mark.parametrize("is_windows", [True, False])
def test_create_reflex_dir(mocker, is_windows): def test_create_reflex_dir(mocker, is_windows):
"""Test that a reflex directory is created on initializing frontend """Test that a reflex directory is created on initializing frontend
@ -572,7 +589,7 @@ def test_create_reflex_dir(mocker, is_windows):
mocker: Pytest mocker object. mocker: Pytest mocker object.
is_windows: Whether platform is windows. is_windows: Whether platform is windows.
""" """
mocker.patch("reflex.utils.prerequisites.IS_WINDOWS", is_windows) mocker.patch("reflex.utils.prerequisites.constants.IS_WINDOWS", is_windows)
mocker.patch("reflex.utils.prerequisites.processes.run_concurrently", mocker.Mock()) mocker.patch("reflex.utils.prerequisites.processes.run_concurrently", mocker.Mock())
mocker.patch("reflex.utils.prerequisites.initialize_web_directory", mocker.Mock()) mocker.patch("reflex.utils.prerequisites.initialize_web_directory", mocker.Mock())
create_cmd = mocker.patch( create_cmd = mocker.patch(
@ -581,7 +598,4 @@ def test_create_reflex_dir(mocker, is_windows):
prerequisites.initialize_frontend_dependencies() prerequisites.initialize_frontend_dependencies()
if is_windows: assert create_cmd.called
assert not create_cmd.called
else:
assert create_cmd.called