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

View File

@ -8,12 +8,16 @@ from enum import Enum
from types import SimpleNamespace
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
try:
from importlib import metadata
except ImportError:
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:
"""Get the value for the constant.
@ -48,7 +52,17 @@ VERSION = metadata.version(MODULE_NAME)
# Files and directories used to init a new project.
# 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.
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# The name of the assets directory.
@ -79,29 +93,38 @@ BUN_INSTALL_URL = "https://bun.sh/install"
# NVM / Node config.
# The NVM version.
NVM_VERSION = "0.39.1"
# The FNM version.
FNM_VERSION = "1.35.1"
# The Node version.
NODE_VERSION = "18.17.0"
# The minimum required node version.
NODE_VERSION_MIN = "16.8.0"
# The directory to store 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.
NVM_PATH = os.path.join(NVM_DIR, "nvm.sh")
# 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.
NODE_PATH = (
"node" if platform.system() == "Windows" else os.path.join(NODE_BIN_PATH, "node")
)
NODE_PATH = os.path.join(NODE_BIN_PATH, "node.exe" if IS_WINDOWS else "node")
# The default path where npm is installed.
NPM_PATH = (
"npm" if platform.system() == "Windows" else os.path.join(NODE_BIN_PATH, "npm")
)
NPM_PATH = os.path.join(NODE_BIN_PATH, "npm")
# The URL to the nvm install script.
NVM_INSTALL_URL = (
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 web folder where the NextJS app is compiled to.
WEB_DIR = ".web"

View File

@ -124,6 +124,7 @@ def export(
process = processes.new_process(
[prerequisites.get_package_manager(), "run", command],
cwd=constants.WEB_DIR,
shell=constants.IS_WINDOWS,
)
processes.show_progress("Creating Production Build", process, checkpoints)
@ -201,6 +202,7 @@ def setup_frontend(
],
cwd=constants.WEB_DIR,
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.
"""
process = processes.new_process(
run_command,
cwd=constants.WEB_DIR,
run_command, cwd=constants.WEB_DIR, shell=constants.IS_WINDOWS
)
if process.stdout:
@ -137,7 +136,7 @@ def run_backend_prod(
str(port),
f"{app_name}:{constants.APP_VAR}",
]
if prerequisites.IS_WINDOWS
if constants.IS_WINDOWS
else [
*constants.RUN_BACKEND_PROD,
"--bind",

View File

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

View File

@ -1,6 +1,6 @@
"""Unit tests for the included testing tools."""
from reflex.constants import IS_WINDOWS
from reflex.testing import AppHarness
from reflex.utils.prerequisites import IS_WINDOWS
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()
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.
Args:
tmp_path: Test working dir.
mocker: Pytest mocker object.
"""
mocker.patch("reflex.utils.prerequisites.IS_WINDOWS", True)
mocker.patch("reflex.utils.prerequisites.check_node_version", return_value=False)
fnm_root_path = tmp_path / "reflex" / "fnm"
fnm_exe = fnm_root_path / "fnm.exe"
with pytest.raises(typer.Exit):
prerequisites.install_node()
mocker.patch("reflex.utils.prerequisites.constants.FNM_DIR", fnm_root_path)
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):
nvm_root_path = tmp_path / ".reflex" / ".nvm"
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):
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("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):
prerequisites.install_bun()
# from
@pytest.mark.parametrize("is_windows", [True, False])
def test_create_reflex_dir(mocker, is_windows):
"""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.
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.initialize_web_directory", mocker.Mock())
create_cmd = mocker.patch(
@ -581,7 +598,4 @@ def test_create_reflex_dir(mocker, is_windows):
prerequisites.initialize_frontend_dependencies()
if is_windows:
assert not create_cmd.called
else:
assert create_cmd.called
assert create_cmd.called