diff --git a/.gitignore b/.gitignore index 5497dabb14..6afc1003f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,14 @@ debug.json debug.js target/ + +# Ignore all files in schemas/ except specific JSON schemas and supporting files +schemas/* +!schemas/pyproject-tool-pyrefly.json +!schemas/pyrefly.json +!schemas/validate_schemas.py +!schemas/test-pyrefly.toml +!schemas/test-pyproject.toml +!schemas/README.md +!schemas/CONTRIBUTING.md +!schemas/SCHEMASTORE.md diff --git a/schemas/CONTRIBUTING.md b/schemas/CONTRIBUTING.md new file mode 100644 index 0000000000..8a004afa8a --- /dev/null +++ b/schemas/CONTRIBUTING.md @@ -0,0 +1,173 @@ +# Contributing to Pyrefly Schemas + +Thank you for your interest in improving Pyrefly's JSON Schema definitions! + +## Overview + +The schemas in this directory provide validation, autocomplete, and documentation for Pyrefly configuration files. When updating the schemas, it's important to keep them in sync with the actual configuration implementation. + +## Schema Files + +- **pyrefly.json**: Schema for standalone `pyrefly.toml` files +- **pyproject-tool-pyrefly.json**: Schema for the `[tool.pyrefly]` section in `pyproject.toml` + +Both schemas should have identical configuration options, just wrapped differently. + +## When to Update Schemas + +Update the schemas whenever: + +1. **New configuration options are added** to Pyrefly +2. **Configuration options are modified** (renamed, type changed, etc.) +3. **Configuration options are deprecated or removed** +4. **Default values change** +5. **Enum values are added or removed** + +## How to Update Schemas + +### 1. Check the Source of Truth + +The authoritative source for configuration options is: +- `crates/pyrefly_config/src/config.rs` - Main config structure +- `crates/pyrefly_config/src/base.rs` - Base config options +- `website/docs/configuration.mdx` - User-facing documentation + +Always verify your changes against these sources. + +### 2. Update Both Schema Files + +When adding a new configuration option, update both: +- `pyrefly.json` at the top level +- `pyproject-tool-pyrefly.json` under `properties.tool.properties.pyrefly.properties` + +Ensure the option definitions are identical. + +### 3. Follow JSON Schema Best Practices + +- **Use descriptive descriptions**: Each property should have a clear description +- **Set appropriate types**: Use `string`, `boolean`, `array`, `object`, etc. +- **Add default values**: Include the actual default value from the Rust code +- **Use enums for fixed values**: For options like `python-platform` or `untyped-def-behavior` +- **Add patterns for validation**: For example, version strings should match `^\d+(\.\d+)?(\.\d+)?$` +- **Mark required properties**: Use `required` array for mandatory fields + +### 4. Add Test Cases + +Add examples of the new configuration option to the test files: +- `test-pyrefly.toml` - Examples for `pyrefly.toml` +- `test-pyproject.toml` - Examples for `pyproject.toml` + +### 5. Validate Your Changes + +Run the validation script to ensure the schemas are correct: + +```bash +python schemas/validate_schemas.py +``` + +This script validates the test configuration files against the schemas. + +### 6. Update Documentation + +If you're adding a new configuration option, also update: +- `schemas/README.md` - If the change affects how users interact with schemas +- `website/docs/configuration.mdx` - User-facing documentation (if not already done) + +## Schema Structure + +### Common Properties Format + +```json +"property-name": { + "description": "Clear description of what this does", + "type": "string|boolean|array|object|number", + "default": , + "enum": ["value1", "value2"], // For fixed set of values + "pattern": "regex", // For string validation + "items": {...}, // For array element types + "properties": {...} // For object properties +} +``` + +### Naming Conventions + +- Use kebab-case for property names: `python-version`, not `python_version` +- Match the exact names used in the TOML configuration +- For deprecated options, add a note in the description + +### Example: Adding a New Boolean Option + +```json +"new-option-name": { + "description": "Whether to enable the new feature. Default is false.", + "type": "boolean", + "default": false +} +``` + +### Example: Adding a New Enum Option + +```json +"new-mode": { + "description": "The mode to use for the new feature.", + "type": "string", + "enum": ["strict", "lenient", "off"], + "default": "lenient" +} +``` + +### Example: Adding a New Array Option + +```json +"new-patterns": { + "description": "List of glob patterns for the new feature.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] +} +``` + +## Testing + +### Manual Testing + +1. Create a test configuration file with the new option +2. Open it in VS Code with the "Even Better TOML" extension +3. Verify that: + - Autocomplete suggests the new option + - Hover shows the correct description + - Invalid values are highlighted + - Default value is documented + +### Automated Testing + +The `validate_schemas.py` script validates test files against schemas: + +```bash +# Install dependencies (if not already installed) +pip install jsonschema toml + +# Run validation +python schemas/validate_schemas.py +``` + +Add test cases to `test-pyrefly.toml` and `test-pyproject.toml` that exercise your new configuration option. + +## Submitting Changes + +1. **Create a branch**: `git checkout -b update-schema-` +2. **Make your changes**: Update both schema files +3. **Add tests**: Update test configuration files +4. **Validate**: Run `python schemas/validate_schemas.py` +5. **Format**: Ensure JSON files are properly formatted (2-space indentation) +6. **Commit**: Write a clear commit message explaining the change +7. **Submit PR**: Create a pull request with a description of what was added/changed + +## Questions? + +If you have questions about updating the schemas: +- Check existing schema definitions for similar patterns +- Review the [JSON Schema documentation](https://json-schema.org/) +- Open an issue or ask on [Discord](https://discord.com/invite/Cf7mFQtW7W) diff --git a/schemas/README.md b/schemas/README.md new file mode 100644 index 0000000000..0918fe8348 --- /dev/null +++ b/schemas/README.md @@ -0,0 +1,93 @@ +# Pyrefly JSON Schemas + +This directory contains JSON Schema definitions for Pyrefly configuration files. + +## Available Schemas + +### pyrefly.json +JSON Schema for `pyrefly.toml` configuration files. This schema provides validation, autocomplete, and documentation for all Pyrefly configuration options when editing `pyrefly.toml` files. + +**Schema URL:** `https://pyrefly.org/schemas/pyrefly.json` + +### pyproject-tool-pyrefly.json +JSON Schema for the `[tool.pyrefly]` section in `pyproject.toml` files. This schema provides the same validation and autocomplete features as the pyrefly.json schema, but formatted for use within pyproject.toml files. + +**Schema URL:** `https://pyrefly.org/schemas/pyproject-tool-pyrefly.json` + +## Editor Integration + +### VS Code + +VS Code will automatically detect and use these schemas when you have the appropriate extensions installed: + +1. **For pyrefly.toml files:** + - Install the "Even Better TOML" extension + - Add the following to your `settings.json`: + ```json + { + "evenBetterToml.schema.associations": { + "pyrefly.toml": "https://pyrefly.org/schemas/pyrefly.json" + } + } + ``` + +2. **For pyproject.toml files:** + - The "Even Better TOML" extension automatically supports `[tool.pyrefly]` sections + - No additional configuration needed + +### PyCharm / IntelliJ + +PyCharm automatically recognizes TOML schemas. You can configure schema mappings in: +- Settings → Languages & Frameworks → Schemas and DTDs → JSON Schema Mappings + +### Other Editors + +Most modern editors with TOML support can use JSON Schemas. Consult your editor's documentation for configuring custom schema mappings. + +## Using Schemas Locally + +During development, you can reference the local schema files: + +**For pyrefly.toml:** +Add a comment at the top of your `pyrefly.toml`: +```toml +# yaml-language-server: $schema=./schemas/pyrefly.json +``` + +**For pyproject.toml:** +Add a comment in the `[tool.pyrefly]` section: +```toml +[tool.pyrefly] +# yaml-language-server: $schema=./schemas/pyproject-tool-pyrefly.json +``` + +## Schema Features + +The schemas provide: + +- **Validation**: Ensures your configuration follows the correct structure and types +- **Autocomplete**: Suggests available configuration options as you type +- **Documentation**: Shows descriptions and default values for each configuration option +- **Type Checking**: Validates that values match expected types (strings, arrays, booleans, etc.) +- **Enum Validation**: Ensures enum values (like `python-platform` or `untyped-def-behavior`) are valid + +## Contributing to Schemas + +When adding new configuration options to Pyrefly: + +1. Update the schema files in this directory +2. Ensure the schema matches the actual config structure in `crates/pyrefly_config/` +3. Update the configuration documentation in `website/docs/configuration.mdx` +4. Test the schema with sample configs + +## Submitting to SchemaStore + +These schemas can be submitted to [SchemaStore](https://github.com/SchemaStore/schemastore) to provide automatic validation in all compatible editors without manual configuration. + +To submit: +1. Fork the SchemaStore repository +2. Add the schema files to the `src/schemas/json/` directory +3. Update the `src/api/json/catalog.json` to register the schemas +4. Submit a pull request + +For more information, see the [SchemaStore contribution guide](https://github.com/SchemaStore/schemastore/blob/master/CONTRIBUTING.md). diff --git a/schemas/SCHEMASTORE.md b/schemas/SCHEMASTORE.md new file mode 100644 index 0000000000..d5bbffe48c --- /dev/null +++ b/schemas/SCHEMASTORE.md @@ -0,0 +1,134 @@ +# SchemaStore Submission Guide + +This guide explains how to submit Pyrefly's JSON schemas to [SchemaStore](https://github.com/SchemaStore/schemastore), which will enable automatic schema validation in all compatible editors without manual configuration. + +## What is SchemaStore? + +SchemaStore is a community-driven repository of JSON schemas for configuration files. When a schema is added to SchemaStore, most major editors (VS Code, JetBrains IDEs, Neovim, etc.) automatically provide validation, autocomplete, and documentation for the associated file types. + +## Prerequisites + +Before submitting to SchemaStore, ensure: + +1. ✅ The schemas are well-tested with sample configurations +2. ✅ The schemas follow JSON Schema Draft-07 specification +3. ✅ Documentation is complete and accurate +4. ✅ The schemas are hosted at a stable URL (e.g., `https://pyrefly.org/schemas/`) + +## Submission Steps + +### 1. Host the Schemas + +The schemas need to be publicly accessible at stable URLs. The recommended approach is to host them on the Pyrefly website: + +- `https://pyrefly.org/schemas/pyrefly.json` +- `https://pyrefly.org/schemas/pyproject-tool-pyrefly.json` + +### 2. Fork SchemaStore + +```bash +git clone https://github.com/SchemaStore/schemastore.git +cd schemastore +git checkout -b add-pyrefly-schemas +``` + +### 3. Add Schemas to Catalog + +Edit `src/api/json/catalog.json` and add entries for both schemas: + +```json +{ + "name": "Pyrefly Configuration", + "description": "Configuration file for Pyrefly, a fast Python language server and type checker", + "fileMatch": ["pyrefly.toml", ".pyrefly.toml"], + "url": "https://pyrefly.org/schemas/pyrefly.json" +}, +{ + "name": "Pyrefly Configuration (pyproject.toml)", + "description": "Pyrefly configuration in pyproject.toml under [tool.pyrefly]", + "fileMatch": ["pyproject.toml"], + "url": "https://pyrefly.org/schemas/pyproject-tool-pyrefly.json" +} +``` + +### 4. (Optional) Add Local Copies + +While not strictly required, SchemaStore appreciates having local copies of schemas for backup and faster access: + +```bash +cp schemas/pyrefly.json schemastore/src/schemas/json/pyrefly.json +cp schemas/pyproject-tool-pyrefly.json schemastore/src/schemas/json/pyproject-tool-pyrefly.json +``` + +If adding local copies, update the catalog entries to use local paths: + +```json +{ + "name": "Pyrefly Configuration", + "description": "Configuration file for Pyrefly, a fast Python language server and type checker", + "fileMatch": ["pyrefly.toml", ".pyrefly.toml"], + "url": "https://json.schemastore.org/pyrefly.json" +} +``` + +### 5. Test the Schemas + +SchemaStore has automated tests. Run them to ensure your schemas are valid: + +```bash +npm install +npm test +``` + +### 6. Create Pull Request + +Commit your changes and create a pull request: + +```bash +git add . +git commit -m "Add Pyrefly configuration schemas" +git push origin add-pyrefly-schemas +``` + +Then create a PR on GitHub with: + +- **Title**: "Add Pyrefly configuration schemas" +- **Description**: Explain what Pyrefly is and link to the documentation +- **Checklist**: Confirm you've followed all SchemaStore contribution guidelines + +### 7. Respond to Feedback + +SchemaStore maintainers may request changes. Common feedback includes: + +- Improving descriptions +- Adding more specific validation patterns +- Ensuring enum values are complete +- Fixing schema validation errors + +## Maintenance + +Once accepted, you'll need to keep the schemas updated: + +1. When adding new config options, update both the local schemas and the hosted versions +2. Create a new PR to SchemaStore if the schema URL changes +3. Monitor issues on the SchemaStore repo for user-reported problems + +## Alternative: TOML-Specific Editors + +Some TOML-specific editors (like the "Even Better TOML" VS Code extension) support schema associations without SchemaStore. These are configured via: + +**VS Code settings.json:** +```json +{ + "evenBetterToml.schema.associations": { + "pyrefly.toml": "https://pyrefly.org/schemas/pyrefly.json", + "pyproject.toml": "https://pyrefly.org/schemas/pyproject-tool-pyrefly.json" + } +} +``` + +## References + +- [SchemaStore Repository](https://github.com/SchemaStore/schemastore) +- [SchemaStore Contributing Guide](https://github.com/SchemaStore/schemastore/blob/master/CONTRIBUTING.md) +- [JSON Schema Specification](https://json-schema.org/specification.html) diff --git a/schemas/pyproject-tool-pyrefly.json b/schemas/pyproject-tool-pyrefly.json new file mode 100644 index 0000000000..62cc329df1 --- /dev/null +++ b/schemas/pyproject-tool-pyrefly.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://pyrefly.org/schemas/pyproject-tool-pyrefly.json", + "title": "Pyrefly Configuration in pyproject.toml", + "description": "Configuration for Pyrefly under the [tool.pyrefly] section in pyproject.toml", + "type": "object", + "properties": { + "tool": { + "type": "object", + "properties": { + "pyrefly": { + "$ref": "pyrefly.json" + } + } + } + } +} diff --git a/schemas/pyrefly.json b/schemas/pyrefly.json new file mode 100644 index 0000000000..85fa604e02 --- /dev/null +++ b/schemas/pyrefly.json @@ -0,0 +1,297 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://pyrefly.org/schemas/pyrefly.json", + "title": "Pyrefly Configuration", + "description": "Configuration file for Pyrefly, a fast Python language server and type checker", + "type": "object", + "$defs": { + "configBase": { + "type": "object", + "properties": { + "errors": { + "description": "Configure the severity for each kind of error that Pyrefly emits. Set error code to true to enable (default severity), false to disable, or use a severity string ('ignore', 'info', 'warn', 'error'). Any valid Pyrefly error code can be used, not just the ones listed here.", + "type": "object", + "additionalProperties": { + "oneOf": [ + { "type": "boolean" }, + { "type": "string", "enum": ["ignore", "info", "warn", "error"] } + ] + }, + "properties": { + "bad-assignment": {}, + "bad-return": {}, + "missing-import": {}, + "invalid-argument": {}, + "assert-type": {}, + "bad-override": {}, + "incompatible-type": {}, + "unused-import": {}, + "undefined-variable": {} + }, + "default": {} + }, + "disable-type-errors-in-ide": { + "description": "Disables type errors from showing up when running Pyrefly in an IDE. This is primarily used when Pyrefly is acting in a language-server-only mode.", + "type": "boolean", + "default": false + }, + "replace-imports-with-any": { + "description": "Instruct Pyrefly to unconditionally replace the given module globs with typing.Any and ignore import errors for the module.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "ignore-missing-imports": { + "description": "Instruct Pyrefly to replace the given module globs with typing.Any and ignore import errors for the module only when the module can't be found.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "ignore-errors-in-generated-code": { + "description": "Whether to ignore type errors in generated code. If enabled, generated files will be treated as if they are included in project-excludes. The generated code status is determined by checking if the file contents contain the substring '@generated'.", + "type": "boolean", + "default": false + }, + "infer-with-first-use": { + "description": "Whether to infer type variables not determined by a call or constructor based on their first usage. This includes empty containers like [] and {}. Default behavior is similar to Mypy.", + "type": "boolean", + "default": true + }, + "untyped-def-behavior": { + "description": "How should Pyrefly treat function definitions with no parameter or return type annotations?", + "type": "string", + "enum": ["check-and-infer-return-type", "check-and-infer-return-any", "skip-and-infer-return-any"], + "default": "check-and-infer-return-type" + }, + "permissive-ignores": { + "description": "Should Pyrefly ignore errors based on annotations from other tools, e.g. # pyre-ignore or # mypy: ignore? By default, respects # pyrefly: ignore and # type: ignore.", + "type": "boolean", + "default": false + }, + "enabled-ignores": { + "description": "What set of tools should Pyrefly respect ignore directives from?", + "type": "array", + "items": { + "type": "string", + "enum": ["type", "pyrefly", "mypy", "pyright", "pyre", "ty"] + }, + "default": ["type", "pyrefly"] + }, + "tensor-shapes": { + "description": "Whether to enable tensor shape checking.", + "type": "boolean" + }, + "recursion-depth-limit": { + "description": "Maximum recursion depth for type evaluation. Set to 0 to disable the limit.", + "type": "integer", + "minimum": 0 + }, + "recursion-overflow-handler": { + "description": "How should Pyrefly handle recursion overflow during type evaluation?", + "type": "string", + "enum": ["break-with-placeholder", "panic-with-debug-info"], + "default": "break-with-placeholder" + } + } + } + }, + "allOf": [ + { + "$ref": "#/$defs/configBase" + }, + { + "type": "object", + "properties": { + "project-includes": { + "description": "The glob patterns used to describe which files to type check, typically understood as user-space files. This does not specify import resolution priority.", + "type": "array", + "items": { + "type": "string" + }, + "default": ["**/*.py*", "**/*.ipynb"] + }, + "project-excludes": { + "description": "The glob patterns used to describe which files to avoid type checking as a way to filter files that match project-includes.", + "type": "array", + "items": { + "type": "string" + }, + "default": ["**/node_modules", "**/__pycache__", "**/venv/**", "**/.[!/.]*/**"] + }, + "disable-project-excludes-heuristics": { + "description": "Disable automatic appending of default project-excludes patterns. When true, you have full control over project-excludes.", + "type": "boolean", + "default": false + }, + "search-path": { + "description": "A list of directory paths describing the roots from which imports should be found and imported from. This takes the highest precedence in import order, before typeshed and site-package-path.", + "type": "array", + "items": { + "type": "string" + }, + "default": ["."] + }, + "disable-search-path-heuristics": { + "description": "Disable any search path heuristics/additional search path behavior that Pyrefly will attempt to do for you.", + "type": "boolean", + "default": false + }, + "site-package-path": { + "description": "A list of directory paths describing roots from which imports should be found and imported from. This takes the lowest priority in import resolution, after search-path and typeshed.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "python-platform": { + "description": "The value used with conditions based on type checking against sys.platform values. Common values include 'linux', 'darwin', 'win32', but any valid sys.platform string is accepted.", + "type": "string", + "default": "linux", + "examples": ["linux", "darwin", "win32", "cygwin", "freebsd", "openbsd", "netbsd", "aix"] + }, + "python-version": { + "description": "The Python version to use for type checking. Format: [.[.]]", + "type": "string", + "default": "3.13.0", + "pattern": "^\\d+(\\.\\d+)?(\\.\\d+)?$" + }, + "conda-environment": { + "description": "The name of the Conda environment to query when attempting to autoconfigure Python environment values.", + "type": "string" + }, + "python-interpreter-path": { + "description": "The Python interpreter to query when attempting to autoconfigure Python environment values (site-package-path, python-platform, python-version).", + "type": "string" + }, + "fallback-python-interpreter-name": { + "description": "The Python interpreter, available on your $PATH, to use. Pyrefly will perform 'which ', and automatically fill in python-interpreter-path for you with the found path.", + "type": "string" + }, + "skip-interpreter-query": { + "description": "Skip querying any interpreters and do not do any environment autoconfiguration. This means that Pyrefly will take hard-coded defaults for python-version and python-platform, and will use an empty site-package-path.", + "type": "boolean", + "default": false + }, + "typeshed-path": { + "description": "Override the version of typeshed that's being used for type checking. The provided path should point to the root of typeshed.", + "type": "string" + }, + "use-ignore-files": { + "description": "Whether to allow Pyrefly to use ignore files in your project and automatically add excluded files and directories to your project-excludes.", + "type": "boolean", + "default": true + }, + "skip-lsp-config-indexing": { + "description": "Should Pyrefly try to index the project's files? Disabling this may speed up LSP operations on large projects.", + "type": "boolean", + "default": false + }, + "baseline": { + "description": "Path to a baseline file for suppressing existing errors.", + "type": "string" + }, + "build-system": { + "description": "Pyrefly supports integrating into build systems to discover targets to type check and their dependencies. Currently supports Buck2 and custom queries.", + "type": "object", + "properties": { + "type": { + "description": "The type of build system.", + "type": "string", + "enum": ["buck", "custom"] + }, + "ignore-if-build-system-missing": { + "description": "Whether to silently ignore the build system configuration if the build system is not found.", + "type": "boolean", + "default": false + }, + "search-path-prefix": { + "description": "Prefix paths to prepend to search paths discovered by the build system.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "isolation-dir": { + "description": "The isolation dir for Buck2 to use.", + "type": "string" + }, + "extras": { + "description": "Extra flags passed to Buck2.", + "type": "array", + "items": { + "type": "string" + } + }, + "command": { + "description": "The command executed to query the build system about available targets.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["type"], + "allOf": [ + { + "if": { + "properties": { + "type": {"const": "buck"} + } + }, + "then": { + "not": { + "required": ["command"] + } + } + }, + { + "if": { + "properties": { + "type": {"const": "custom"} + } + }, + "then": { + "required": ["command"], + "not": { + "anyOf": [ + {"required": ["isolation-dir"]}, + {"required": ["extras"]} + ] + } + } + } + ] + }, + "sub-config": { + "description": "Override specific config values for matched paths in your project. SubConfigs allow fine-grained configuration based on filepath glob matching.", + "type": "array", + "items": { + "allOf": [ + { + "$ref": "#/$defs/configBase" + }, + { + "type": "object", + "required": ["matches"], + "properties": { + "matches": { + "description": "A filesystem glob pattern detailing which files the config applies to.", + "type": "string" + } + } + } + ] + }, + "default": [] + } + } + } + ], + "additionalProperties": true +} diff --git a/schemas/test-pyproject.toml b/schemas/test-pyproject.toml new file mode 100644 index 0000000000..a2a54432df --- /dev/null +++ b/schemas/test-pyproject.toml @@ -0,0 +1,63 @@ +# Test configuration file for pyproject.toml [tool.pyrefly] schema validation + +[project] +name = "example-project" +version = "0.1.0" + +[tool.pyrefly] +# Basic project configuration +project-includes = ["src", "tests"] +project-excludes = ["**/node_modules", "**/__pycache__"] +disable-project-excludes-heuristics = false + +# Import paths +search-path = ["src", "lib"] +disable-search-path-heuristics = false +site-package-path = ["venv/lib/python3.12/site-packages"] + +# Python environment +python-platform = "linux" +python-version = "3.12.0" +skip-interpreter-query = false + +# Type checking behavior +untyped-def-behavior = "check-and-infer-return-type" +infer-with-first-use = true +ignore-errors-in-generated-code = false +disable-type-errors-in-ide = false +tensor-shapes = false +recursion-depth-limit = 100 +recursion-overflow-handler = "break-with-placeholder" + +# Import handling +replace-imports-with-any = ["sympy.*", "*.series"] +ignore-missing-imports = ["numpy.*"] + +# Ignore files and directives +use-ignore-files = true +permissive-ignores = false +enabled-ignores = ["type", "pyrefly"] + +# Baseline +# baseline = "baseline.json" + +# Error configuration +[tool.pyrefly.errors] +bad-assignment = false +bad-return = true +missing-import = "warn" +invalid-argument = "error" + +# SubConfig example 1: Test files +[[tool.pyrefly.sub-config]] +matches = "**/tests/**" +untyped-def-behavior = "skip-and-infer-return-any" + +[tool.pyrefly.sub-config.errors] +assert-type = true + +# SubConfig example 2: Generated code +[[tool.pyrefly.sub-config]] +matches = "**/*_pb2.py" +ignore-errors-in-generated-code = true +replace-imports-with-any = ["google.protobuf.*"] diff --git a/schemas/test-pyrefly.toml b/schemas/test-pyrefly.toml new file mode 100644 index 0000000000..b3c8c257be --- /dev/null +++ b/schemas/test-pyrefly.toml @@ -0,0 +1,62 @@ +# Test configuration file for pyrefly.toml schema validation +# This file contains examples of all configuration options + +# Basic project configuration +project-includes = ["src", "tests"] +project-excludes = ["**/node_modules", "**/__pycache__"] +disable-project-excludes-heuristics = false + +# Import paths +search-path = ["src", "lib"] +disable-search-path-heuristics = false +site-package-path = ["venv/lib/python3.12/site-packages"] + +# Python environment +python-platform = "linux" +python-version = "3.12.0" +skip-interpreter-query = false +# python-interpreter-path = "venv/bin/python3" +# conda-environment = "myenv" +# fallback-python-interpreter-name = "python3" + +# Type checking behavior +untyped-def-behavior = "check-and-infer-return-type" +infer-with-first-use = true +ignore-errors-in-generated-code = false +disable-type-errors-in-ide = false +tensor-shapes = false +recursion-depth-limit = 100 +recursion-overflow-handler = "break-with-placeholder" + +# Import handling +replace-imports-with-any = ["sympy.*", "*.series"] +ignore-missing-imports = ["numpy.*"] + +# Ignore files and directives +use-ignore-files = true +permissive-ignores = false +enabled-ignores = ["type", "pyrefly"] + +# Baseline +# baseline = "baseline.json" + +# Error configuration +[errors] +bad-assignment = false +bad-return = true +missing-import = "warn" +invalid-argument = "error" + +# SubConfig example 1: Test files +[[sub-config]] +matches = "**/tests/**" +untyped-def-behavior = "skip-and-infer-return-any" + +[sub-config.errors] +assert-type = true + +# SubConfig example 2: Generated code +[[sub-config]] +matches = "**/*_pb2.py" +ignore-errors-in-generated-code = true +replace-imports-with-any = ["google.protobuf.*"] diff --git a/schemas/validate_schemas.py b/schemas/validate_schemas.py new file mode 100644 index 0000000000..ab039cd514 --- /dev/null +++ b/schemas/validate_schemas.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +""" +Schema validation test script. + +This script validates the test configuration files against the JSON schemas +to ensure the schemas are correctly structured and comprehensive. + +Requirements: + pip install jsonschema toml referencing +""" + +import json +import sys +from pathlib import Path + +try: + import jsonschema + import referencing + import referencing.jsonschema + import toml +except ImportError: + print("Error: Required packages not installed.") + print("Please run: pip install jsonschema toml referencing") + sys.exit(1) + + +def validate_toml_against_schema(toml_file: Path, schema_file: Path) -> bool: + """Validate a TOML file against a JSON schema.""" + print(f"\n{'='*60}") + print(f"Validating: {toml_file.name}") + print(f"Schema: {schema_file.name}") + print('='*60) + + try: + # Load TOML config + with open(toml_file, 'r') as f: + config = toml.load(f) + + # Load JSON schema + with open(schema_file, 'r') as f: + schema = json.load(f) + + # For pyproject.toml, extract the tool.pyrefly section + if 'tool' in config and 'pyrefly' in config['tool']: + config_to_validate = config['tool']['pyrefly'] + print("Validating [tool.pyrefly] section") + else: + config_to_validate = config + print("Validating pyrefly.toml config") + + # Validate using a resolver for $ref support + schema_uri = Path(schema_file).resolve().as_uri() + resource = referencing.Resource.from_contents(schema, default_specification=referencing.jsonschema.DRAFT7) + registry = referencing.Registry().with_resource(schema_uri, resource) + if "$id" in schema: + registry = registry.with_resource(schema["$id"], resource) + validator_cls = jsonschema.validators.validator_for(schema) + validator = validator_cls(schema, registry=registry) + validator.validate(config_to_validate) + + print(" Validation PASSED") + return True + + except jsonschema.ValidationError as e: + print(f"❌ Validation FAILED") + print(f"\nError: {e.message}") + if e.path: + print(f"Path: {' -> '.join(str(p) for p in e.path)}") + if e.schema_path: + print(f"Schema path: {' -> '.join(str(p) for p in e.schema_path)}") + return False + + except Exception as e: + print(f" Error during validation: {e}") + return False + + +def main(): + """Run all validation tests.""" + schemas_dir = Path(__file__).parent + + tests = [ + (schemas_dir / "test-pyrefly.toml", schemas_dir / "pyrefly.json"), + (schemas_dir / "test-pyproject.toml", schemas_dir / "pyproject-tool-pyrefly.json"), + ] + + print("Starting schema validation tests...") + results = [] + + for toml_file, schema_file in tests: + if not toml_file.exists(): + print(f"\n Warning: Test file not found: {toml_file}") + continue + if not schema_file.exists(): + print(f"\n Warning: Schema file not found: {schema_file}") + continue + + results.append(validate_toml_against_schema(toml_file, schema_file)) + + # Summary + print(f"\n{'='*60}") + print("SUMMARY") + print('='*60) + passed = sum(results) + total = len(results) + print(f"Tests passed: {passed}/{total}") + + if passed == total: + print("\n All tests passed!") + return 0 + else: + print(f"\n {total - passed} test(s) failed") + return 1 + + +if __name__ == "__main__": + sys.exit(main())