Skip to content

Commit a865dc3

Browse files
committed
Quality tool chain and verbosity flags
1 parent 63b186e commit a865dc3

19 files changed

Lines changed: 223 additions & 62 deletions

.github/workflows/ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ jobs:
6161
run: |
6262
python -m pip install --upgrade pip
6363
pip install -e ".[dev]"
64-
pip install ruff mypy
6564
6665
- name: Run Ruff (linter)
6766
run: |

.pre-commit-config.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Pre-commit hooks for synesis (compiler).
2+
# Install: pip install pre-commit && pre-commit install
3+
# Run on all files: pre-commit run --all-files
4+
#
5+
# Note: ruff-format and mypy are intentionally NOT enforced here yet.
6+
# - ruff-format: deferred until the one-time style reflow lands.
7+
# - mypy: runs in CI (non-blocking) until the type-error backlog is cleared.
8+
repos:
9+
- repo: https://github.com/astral-sh/ruff-pre-commit
10+
rev: v0.15.17
11+
hooks:
12+
- id: ruff
13+
args: [--fix]
14+
15+
- repo: https://github.com/pre-commit/pre-commit-hooks
16+
rev: v5.0.0
17+
hooks:
18+
- id: end-of-file-fixer
19+
- id: trailing-whitespace
20+
- id: check-yaml
21+
- id: check-toml
22+
- id: check-merge-conflict

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,31 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.5.6] - 2026-06-12
9+
10+
### Added
11+
12+
- **Verbosity flags `-v`/`-q` on `synesis` CLI** (`synesis/cli.py`)
13+
- `-v` / `--verbose` (count): raises log level to DEBUG. Repeatable.
14+
- `-q` / `--quiet` (count): lowers to WARNING (`-q`) or ERROR (`-qq`). Repeatable.
15+
- Implemented via `_configure_logging(verbose, quiet)` helper using `logging.basicConfig`.
16+
- `Global Options:` section added to `_build_main_help()` output — consistent with synesis-coder style.
17+
- No impact on compilation output; only controls Python logging channel.
18+
819
## [0.5.5] - 2026-06-11
920

21+
### Added
22+
23+
- **Quality toolchain and CI** (`pyproject.toml`, `.pre-commit-config.yaml`, `.github/workflows/ci.yml`)
24+
- `ruff==0.15.17` and `mypy==1.15.0` added to `dev` extras (pinned, shared across ecosystem).
25+
- `[tool.ruff]`: `line-length=100`, `target-version="py310"`; lint rules `["E","F","I","UP","B","SIM","C4"]`.
26+
- `[tool.mypy]`: `ignore_missing_imports=true`, `disallow_untyped_defs=false` (lenient baseline).
27+
- `.pre-commit-config.yaml`: `ruff` (lint + `--fix`), `ruff-format`, `mypy`, `end-of-file-fixer`, `trailing-whitespace`, `check-yaml`, `check-toml`, `check-merge-conflict`.
28+
- CI workflow (3 OS × 3 Python versions): `test` (pytest + coverage), `lint` (ruff + mypy), `build` (wheel + twine check), `integration` (`synesis --help/--version`).
29+
30+
- **CLI snapshot tests** (`tests/test_cli.py`)
31+
- Subprocess-based tests asserting structural anchors in `--help` output (title, `Usage:`, `Commands:`, subcommand names) and `--version` correctness — serve as regression guard for CLI refactors.
32+
1033
### Changed
1134

1235
- **CLI rewritten with Unix-style output, colors, and English-only interface** (`synesis/cli.py`)

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,20 @@ graph TD
6363
| [synesis-lsp](https://github.com/synesis-lang/synesis-lsp) | Python | Language Server — diagnostics, hover, completion, semantic tokens |
6464
| [synesis-explorer](https://github.com/synesis-lang/synesis-explorer) | JS/TS | VS Code extension — tree views, graph viewer, themes |
6565
| [zotero-synesis-export](https://github.com/synesis-lang/zotero-synesis-export) | JavaScript | Zotero 7 plugin — exports PDF highlights and tags as plain `.syn` (no chains or ontology codes) |
66-
| [synesis2neo4j](https://github.com/synesis-lang/synesis2neo4j) | Python | Import compiled knowledge into Neo4j / Memgraph |
66+
| [synesis-graph](https://github.com/synesis-lang/synesis-graph) | Python | Import compiled knowledge into Neo4j / GraphQLite, render interactive HTML graphs |
6767
| [synesis-coder](https://github.com/synesis-lang/synesis-coder) | Python | AI-assisted annotation — generates fully coded `.syn` files (chains, codes, fields) conforming to the project template |
6868

69+
### Compatibility matrix
70+
71+
Downstream tools pin to the compiler version they require:
72+
73+
| Package | Latest version | Requires `synesis` | Python |
74+
|---|---|---|---|
75+
| synesis | 0.5.5 || ≥3.10 |
76+
| synesis-coder | 0.4.1 | ≥0.5.5 | ≥3.10 |
77+
| synesis-lsp | 0.15.4 | ≥0.5.5 | ≥3.10 |
78+
| synesis-graph | 0.2.0 | ≥0.5.5 | ≥3.10 |
79+
6980
---
7081

7182
## A Complete Example

pyproject.toml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "synesis"
7-
version = "0.5.5"
7+
version = "0.5.6"
88
description = "The confluence of information into intelligence - A DSL compiler that transforms qualitative research annotations into canonical knowledge structures"
99
readme = "README.md"
1010
requires-python = ">=3.10"
@@ -54,6 +54,8 @@ dev = [
5454
"pytest-cov >= 4.0",
5555
"build >= 0.10",
5656
"twine >= 4.0",
57+
"ruff == 0.15.17",
58+
"mypy == 1.15.0",
5759
]
5860

5961
[project.urls]
@@ -70,3 +72,22 @@ synesis = "synesis.cli:main"
7072
where = ["."]
7173
include = ["synesis*"]
7274
exclude = ["out_dir*", "davi_pesquisa*", "bibliometrics*", "examples*"]
75+
76+
[tool.ruff]
77+
line-length = 100
78+
target-version = "py310"
79+
# Generated by Lark — not hand-maintained, exclude from lint/format.
80+
extend-exclude = ["synesis/grammar/synesis_standalone.py"]
81+
82+
[tool.ruff.lint]
83+
# Lenient baseline: bug-catching rules (F) and import sorting (I) are enforced;
84+
# cosmetic/modernization rules are deferred (tracked, to be tightened incrementally).
85+
select = ["F", "I"]
86+
ignore = ["F541"] # f-string-missing-placeholders (cosmetic)
87+
88+
[tool.mypy]
89+
python_version = "3.10"
90+
warn_return_any = true
91+
warn_unused_configs = true
92+
disallow_untyped_defs = false
93+
ignore_missing_imports = true

synesis/__init__.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
Gerado conforme: Especificacao Synesis v1.1
2424
"""
2525

26-
from importlib.metadata import PackageNotFoundError, version as _pkg_version
27-
from pathlib import Path
2826
import re
27+
from importlib.metadata import PackageNotFoundError
28+
from importlib.metadata import version as _pkg_version
29+
from pathlib import Path
2930

3031

3132
def _read_version_from_pyproject() -> str:
@@ -39,40 +40,40 @@ def _read_version_from_pyproject() -> str:
3940

4041
# API em memoria (NOVO)
4142
from synesis.api import (
42-
load,
43-
compile_string,
44-
MemoryCompilationResult,
4543
CompilationStats,
46-
)
47-
48-
# Compilador tradicional
49-
from synesis.compiler import (
50-
SynesisCompiler,
51-
CompilationResult,
44+
MemoryCompilationResult,
45+
compile_string,
46+
load,
5247
)
5348

5449
# AST Nodes
5550
from synesis.ast.nodes import (
56-
Scope,
51+
ChainNode,
52+
FieldSpec,
5753
FieldType,
58-
SourceLocation,
59-
ProjectNode,
60-
SourceNode,
54+
IncludeNode,
6155
ItemNode,
6256
OntologyNode,
63-
TemplateNode,
64-
FieldSpec,
65-
ChainNode,
66-
IncludeNode,
6757
OrderedValue,
58+
ProjectNode,
59+
Scope,
60+
SourceLocation,
61+
SourceNode,
62+
TemplateNode,
6863
)
6964

7065
# Result types
7166
from synesis.ast.results import (
72-
Ok,
7367
Err,
74-
ValidationResult,
68+
Ok,
7569
ValidationError,
70+
ValidationResult,
71+
)
72+
73+
# Compilador tradicional
74+
from synesis.compiler import (
75+
CompilationResult,
76+
SynesisCompiler,
7677
)
7778

7879
# Semantic

synesis/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
from synesis.parser.lexer import parse_string
5252
from synesis.parser.template_loader import load_template_from_string
5353
from synesis.parser.transformer import SynesisTransformer
54-
from synesis.semantic.linker import Linker, LinkedProject
54+
from synesis.semantic.linker import LinkedProject, Linker
5555
from synesis.semantic.validator import SemanticValidator
5656

5757

synesis/cli.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from __future__ import annotations
2828

29+
import logging
2930
import sys
3031
import threading
3132
import time
@@ -48,7 +49,6 @@
4849
from synesis.parser.lexer import SynesisSyntaxError, parse_file
4950
from synesis.parser.template_loader import TemplateLoadError, load_template
5051

51-
5252
# ---------------------------------------------------------------------------
5353
# Helpers de estilo
5454
# ---------------------------------------------------------------------------
@@ -61,6 +61,19 @@ def _c(text: str, **kwargs) -> str:
6161
return click.style(text, **kwargs) if _tty() else text
6262

6363

64+
def _configure_logging(verbose: int, quiet: int) -> None:
65+
"""Set root log level: -q → WARNING/ERROR, default → INFO, -v → DEBUG."""
66+
if quiet >= 2:
67+
level = logging.ERROR
68+
elif quiet == 1:
69+
level = logging.WARNING
70+
elif verbose >= 1:
71+
level = logging.DEBUG
72+
else:
73+
level = logging.INFO
74+
logging.basicConfig(level=level, format="[%(levelname)s] %(message)s")
75+
76+
6477
def _build_main_help() -> str:
6578
title = _c("SYNESIS COMPILER", fg="green", bold=True) + f" (v{VERSION})"
6679
desc = "Semantic compiler for knowledge engineering."
@@ -79,7 +92,21 @@ def _build_main_help() -> str:
7992
]),
8093
]
8194

82-
col = max(len(name) for _, rows in groups for name, _ in rows) + 2
95+
opt_rows = [
96+
("-v, --verbose", "Increase log verbosity (DEBUG). Repeatable."),
97+
("-q, --quiet", "Decrease log verbosity (-q WARNING, -qq ERROR). Repeatable."),
98+
("--version", "Show version and exit"),
99+
("--help", "Show this message and exit"),
100+
]
101+
102+
cmd_names_len = max(len(name) for _, rows in groups for name, _ in rows)
103+
opt_names_len = max(len(name) for name, _ in opt_rows)
104+
col = max(cmd_names_len, opt_names_len) + 2
105+
106+
options = _c("Global Options:", fg="yellow", bold=True) + "\n" + "\n".join(
107+
f" {_c(name.ljust(col), fg='cyan')} {desc_}"
108+
for name, desc_ in opt_rows
109+
)
83110

84111
def _render_group(label, rows):
85112
lines = [_c(" " + label, fg="yellow", bold=True)]
@@ -96,7 +123,7 @@ def _render_group(label, rows):
96123
fg="bright_black",
97124
)
98125

99-
return "\n\n".join([title, desc, usage, commands, hint]) + "\n"
126+
return "\n\n".join([title, desc, usage, options, commands, hint]) + "\n"
100127

101128

102129
class _SynesisCommand(click.Command):
@@ -248,9 +275,14 @@ def fail(self) -> None:
248275

249276
@click.group(cls=_SynesisGroup, invoke_without_command=True)
250277
@click.version_option(version=VERSION, prog_name="synesis")
278+
@click.option("-v", "--verbose", count=True, default=0,
279+
help="Increase log verbosity (-v for DEBUG). Repeatable.")
280+
@click.option("-q", "--quiet", count=True, default=0,
281+
help="Decrease log verbosity (-q for WARNING, -qq for ERROR). Repeatable.")
251282
@click.pass_context
252-
def main(ctx) -> None:
283+
def main(ctx, verbose: int, quiet: int) -> None:
253284
"""Compilador semântico para validação e consolidação de conhecimento."""
285+
_configure_logging(verbose, quiet)
254286
if ctx.invoked_subcommand is None:
255287
out = _build_main_help()
256288
if hasattr(sys.stdout, "buffer"):
@@ -594,7 +626,6 @@ def init() -> None:
594626

595627

596628
def _print_diagnostics(errors: Iterable, severity_label: str, base_dir: Path | None = None) -> None:
597-
color = "red" if severity_label == "ERROR" else "yellow"
598629
label_color = "red" if severity_label == "ERROR" else "yellow"
599630

600631
def _fmt_location(loc) -> str:

synesis/compiler.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from concurrent.futures import ProcessPoolExecutor
3333
from dataclasses import dataclass
3434
from pathlib import Path
35-
from typing import Dict, Iterable, List, Optional
35+
from typing import Dict, List, Optional
3636

3737
from synesis.ast.nodes import (
3838
ItemNode,
@@ -42,7 +42,6 @@
4242
SourceNode,
4343
TemplateNode,
4444
)
45-
from synesis.parser.bib_loader import BibEntry
4645
from synesis.ast.results import (
4746
DuplicateProjectBlock,
4847
MalformedBibliographyEntry,
@@ -58,12 +57,12 @@
5857
from synesis.exporters.csv_export import export_csv
5958
from synesis.exporters.json_export import export_json
6059
from synesis.exporters.xls_export import export_xls
61-
from synesis.parser.bib_loader import detect_malformed_entries, load_bibliography
60+
from synesis.parser.bib_loader import BibEntry, detect_malformed_entries, load_bibliography
6261
from synesis.parser.lexer import parse_file
6362
from synesis.parser.parse_cache import get_cached_nodes, put_cached_nodes
6463
from synesis.parser.template_loader import load_template, validate_template
6564
from synesis.parser.transformer import SynesisTransformer
66-
from synesis.semantic.linker import Linker, LinkedProject
65+
from synesis.semantic.linker import LinkedProject, Linker
6766
from synesis.semantic.validator import SemanticValidator
6867

6968

@@ -388,7 +387,7 @@ def _safe_load_template(self, project: ProjectNode) -> tuple[Optional[TemplateNo
388387
return None, result
389388
try:
390389
return load_template(template_path), result
391-
except Exception as exc:
390+
except Exception:
392391
result.add(MissingTemplateFile(
393392
location=project.location,
394393
template_path=str(project.template_path),

synesis/exporters/alpaca_export.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,15 @@
4040
FieldSpec,
4141
FieldType,
4242
ItemNode,
43-
OntologyNode,
4443
Scope,
45-
SourceNode,
4644
TemplateNode,
4745
)
48-
from synesis.parser.bib_loader import BibEntry
49-
from synesis.semantic.linker import LinkedProject
5046
from synesis.exporters._helpers import (
51-
_get_field_names_for_scope,
5247
_get_item_field_value,
5348
_get_ontology_field_value,
5449
)
50+
from synesis.parser.bib_loader import BibEntry
51+
from synesis.semantic.linker import LinkedProject
5552

5653
AlpacaPair = Dict[str, str]
5754
_MIN_OUTPUT_LEN = 5

0 commit comments

Comments
 (0)