# Vera Syntaxis
A static analysis tool for detecting architectural code smells in Python codebases.
## Overview
Vera Syntaxis is a specialized linter that focuses on architectural issues rather than style or type safety:
- **Tight Coupling Detection**: Identifies instances of tight coupling between classes
- **MVBC Architecture Linter**: Enforces communication rules between Model, View, Business, and Controller layers
## Features
- **AST-based Analysis**: Uses Python's Abstract Syntax Tree for accurate code analysis
- **Call Graph Construction**: Builds a comprehensive call graph of your codebase
- **Configurable Rules**: Customize architectural rules via TOML configuration
- **Python API**: Use as a library in your own tools
- **GUI Interface**: Optional GUI plugin for Extensio Pulchra framework
## Requirements
- Python 3.8+
- Extensive use of type hints in target codebase for accurate analysis
## Installation
```bash
pip install vera-syntaxis
```
For development:
```bash
pip install vera-syntaxis[dev]
```
For GUI support:
```bash
pip install vera-syntaxis[gui]
```
## Quick Start
### Command Line
```bash
# Parse and analyze a project
vera-syntaxis analyze /path/to/project
# Parse only (for debugging)
vera-syntaxis parse /path/to/project
```
### Python API
```python
from vera_syntaxis import run_analysis
violations = run_analysis("/path/to/project")
for violation in violations:
print(f"{violation.file_path}:{violation.line_number} - {violation.message}")
```
## Configuration
Create a `pyproject.toml` in your project root:
```toml
[tool.vera_syntaxis]
model_paths = ["my_app/models/"]
view_paths = ["my_app/views/"]
business_paths = ["my_app/services/"]
controller_paths = ["my_app/controllers/"]
module_filter = ["my_app.*"]
[tool.vera_syntaxis.coupling]
max_inter_class_calls = 5
max_demeter_chain = 3
[tool.vera_syntaxis.circular]
allow_self_cycles = false
max_cycle_length = 10
[tool.vera_syntaxis.god_object]
max_methods = 20
max_attributes = 15
max_lines = 300
[tool.vera_syntaxis.feature_envy]
envy_threshold = 0.5
min_accesses = 3
[tool.vera_syntaxis.data_clump]
min_clump_size = 3
min_occurrences = 2
```
## Architectural Rules
### Tight Coupling Linter
#### TC001: Direct Instantiation
Flags direct class instantiations that create tight coupling.
**Example Violation:**
```python
class UserService:
def create_user(self):
# Bad: Direct instantiation creates tight coupling
db = Database()
return db.save(User())
```
**Fix:** Use dependency injection instead.
#### TC002: Law of Demeter (Method Chaining)
Detects excessive method chaining that violates the Law of Demeter.
**Configuration:**
- `max_demeter_chain`: Maximum allowed chain length (default: 5)
**Example Violation:**
```python
# Bad: Chain length of 4 exceeds configured maximum of 3
country = user.address.city.postal_code.country
```
**Fix:** Break the chain using intermediate variables or add helper methods:
```python
# Good: Use intermediate variables
address = user.address
city = address.city
postal_code = city.postal_code
country = postal_code.country
# Or: Add a helper method
country = user.get_country()
```
#### TC003: Excessive Interaction
Identifies classes with too many inter-class calls using call graph analysis.
**Configuration:**
- `max_inter_class_calls`: Maximum allowed unique method calls to other classes (default: 10)
**Example Violation:**
```python
class Client:
def __init__(self):
self.service_a = ServiceA()
self.service_b = ServiceB()
self.service_c = ServiceC()
def do_work(self):
# Bad: Calls 12 unique methods from other classes (exceeds limit of 10)
self.service_a.method1()
self.service_a.method2()
self.service_a.method3()
self.service_a.method4()
self.service_b.method1()
self.service_b.method2()
self.service_b.method3()
self.service_b.method4()
self.service_c.method1()
self.service_c.method2()
self.service_c.method3()
self.service_c.method4()
```
**Fix:** Refactor to reduce coupling:
```python
# Good: Introduce a facade or coordinator
class ServiceCoordinator:
def __init__(self):
self.service_a = ServiceA()
self.service_b = ServiceB()
self.service_c = ServiceC()
def execute_workflow(self):
# Encapsulates the complex interactions
self.service_a.do_work()
self.service_b.do_work()
self.service_c.do_work()
class Client:
def __init__(self):
self.coordinator = ServiceCoordinator()
def do_work(self):
# Now only 1 inter-class call
self.coordinator.execute_workflow()
```
### MVBC Linter
#### W2902: Illegal Layer Dependency
Enforces proper layer communication in Model-View-Business-Controller architecture.
**Allowed Dependencies:**
- **Model**: Can be used by anyone (no dependencies on other layers)
- **View**: Can use Model only
- **Business**: Can use Model only
- **Controller**: Can use View, Business, and Model
**Forbidden Dependencies:**
- View → Business (must go through Controller)
- Business → View (business logic shouldn't know about presentation)
- View → Controller (creates circular dependency)
- Business → Controller (creates circular dependency)
**Configuration:**
Supports both single-level and nested directory patterns:
```toml
[tool.vera_syntaxis.mvbc]
model_paths = ["models/*.py"] # Matches models/user.py and models/subdir/user.py
view_paths = ["views/**/*.py"] # Explicit nested pattern
business_paths = ["business/*.py"]
controller_paths = ["controllers/*.py"]
```
**Example Violations:**
*View → Business:*
```python
# In views/user_view.py
from business.user_logic import UserLogic # Bad: View importing Business
class UserView:
def __init__(self):
self.logic = UserLogic()
```
**Fix:** Use a Controller to mediate between View and Business.
*Business → View:*
```python
# In business/user_logic.py
from views.user_view import UserView # Bad: Business importing View
class UserLogic:
def __init__(self):
self.view = UserView()
```
**Fix:** Keep business logic independent of presentation. Controllers should manage Views.
### Circular Dependency Linter
#### CD001: Circular Dependency
Detects circular dependencies between modules.
**Configuration:**
- `allow_self_cycles`: Allow methods to call themselves (default: false)
- `max_cycle_length`: Maximum cycle length to report (default: 10)
**Example Violation:**
```python
# module_a.py
from module_b import ClassB
class ClassA:
def method(self):
b = ClassB()
# module_b.py
from module_a import ClassA # Circular dependency!
class ClassB:
def method(self):
a = ClassA()
```
**Fix:** Break the cycle using dependency inversion:
```python
# interface.py
from abc import ABC, abstractmethod
class IProcessor(ABC):
@abstractmethod
def process(self): pass
# module_a.py
from interface import IProcessor
class ClassA(IProcessor):
def process(self):
pass
# module_b.py
from interface import IProcessor
class ClassB:
def __init__(self, processor: IProcessor):
self.processor = processor
```
### God Object Linter
#### GO001: God Object
Detects classes with too many responsibilities (God Objects).
**Configuration:**
- `max_methods`: Maximum number of methods allowed (default: 20)
- `max_attributes`: Maximum number of attributes allowed (default: 15)
- `max_lines`: Maximum number of lines allowed (default: 300)
**Example Violation:**
```python
class UserManager: # God Object!
def __init__(self):
self.db = Database()
self.cache = Cache()
self.logger = Logger()
self.validator = Validator()
self.emailer = Emailer()
# ... 15+ attributes
def create_user(self): pass
def update_user(self): pass
def delete_user(self): pass
def validate_email(self): pass
def send_welcome_email(self): pass
def log_activity(self): pass
# ... 20+ methods
```
**Fix:** Split into focused classes:
```python
# Separate concerns into focused classes
class UserRepository:
def __init__(self, db):
self.db = db
def create(self, user): pass
def update(self, user): pass
def delete(self, user_id): pass
class UserValidator:
def validate_email(self, email): pass
def validate_password(self, password): pass
class UserNotifier:
def __init__(self, emailer):
self.emailer = emailer
def send_welcome_email(self, user): pass
def send_password_reset(self, user): pass
class UserService:
def __init__(self, repo, validator, notifier):
self.repo = repo
self.validator = validator
self.notifier = notifier
def create_user(self, user_data):
if self.validator.validate_email(user_data['email']):
user = self.repo.create(user_data)
self.notifier.send_welcome_email(user)
return user
```
### Feature Envy Linter
#### FE001: Feature Envy
Detects methods that use more features from another class than their own.
**Configuration:**
- `envy_threshold`: Ratio of external to total accesses that triggers envy (default: 0.5)
- `min_accesses`: Minimum total accesses before checking (default: 3)
**Example Violation:**
```python
class Order:
def __init__(self):
self.customer = Customer()
def validate_customer_email(self): # Feature Envy!
# Uses customer features more than own features
email = self.customer.email
email = self.customer.email.strip()
email = self.customer.email.lower()
is_valid = '@' in self.customer.email
return is_valid
```
**Fix:** Move the method to the appropriate class:
```python
class Customer:
def __init__(self):
self.email = ""
def validate_email(self):
# Now uses own features
email = self.email.strip().lower()
return '@' in email
class Order:
def __init__(self):
self.customer = Customer()
def process(self):
# Delegate to the appropriate class
if self.customer.validate_email():
# Process order
pass
```
### Data Clump Linter
#### DC001: Data Clump
Detects groups of parameters that frequently appear together.
**Configuration:**
- `min_clump_size`: Minimum number of parameters in a clump (default: 3)
- `min_occurrences`: Minimum number of methods with the clump (default: 2)
**Example Violation:**
```python
class OrderProcessor:
def calculate_total(self, price, quantity, discount): # Data Clump!
return price * quantity * (1 - discount)
def validate_order(self, price, quantity, discount): # Same parameters
return price > 0 and quantity > 0
def format_order(self, price, quantity, discount): # Same parameters
return f"{quantity} items at ${price}"
```
**Fix:** Extract data clump into a class:
```python
class OrderDetails:
def __init__(self, price: float, quantity: int, discount: float):
self.price = price
self.quantity = quantity
self.discount = discount
def calculate_total(self) -> float:
return self.price * self.quantity * (1 - self.discount)
def validate(self) -> bool:
return self.price > 0 and self.quantity > 0
def format(self) -> str:
return f"{self.quantity} items at ${self.price}"
class OrderProcessor:
def process_order(self, details: OrderDetails):
if details.validate():
total = details.calculate_total()
print(details.format())
return total
```
## Limitations
- Requires extensive type hints for accurate analysis
- Dynamic attributes (via `__getattr__`) may not be detected
- Forward references must be properly annotated
## Development Status
Version 0.1.0 - Alpha (Reporting Only)
## License
MIT License
## Contributing
Contributions welcome! Please see CONTRIBUTING.md for guidelines.
Raw data
{
"_id": null,
"home_page": null,
"name": "vera-syntaxis",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "linter, architecture, code-quality, static-analysis, design-patterns",
"author": "RH Labs/The SurveyOS Project",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/6d/89/58406268bb24e4b8c7befd1e2451f3263449c9a7cff5e75a734173baf4fb/vera_syntaxis-0.1.0.tar.gz",
"platform": null,
"description": "# Vera Syntaxis\r\n\r\nA static analysis tool for detecting architectural code smells in Python codebases.\r\n\r\n## Overview\r\n\r\nVera Syntaxis is a specialized linter that focuses on architectural issues rather than style or type safety:\r\n\r\n- **Tight Coupling Detection**: Identifies instances of tight coupling between classes\r\n- **MVBC Architecture Linter**: Enforces communication rules between Model, View, Business, and Controller layers\r\n\r\n## Features\r\n\r\n- **AST-based Analysis**: Uses Python's Abstract Syntax Tree for accurate code analysis\r\n- **Call Graph Construction**: Builds a comprehensive call graph of your codebase\r\n- **Configurable Rules**: Customize architectural rules via TOML configuration\r\n- **Python API**: Use as a library in your own tools\r\n- **GUI Interface**: Optional GUI plugin for Extensio Pulchra framework\r\n\r\n## Requirements\r\n\r\n- Python 3.8+\r\n- Extensive use of type hints in target codebase for accurate analysis\r\n\r\n## Installation\r\n\r\n```bash\r\npip install vera-syntaxis\r\n```\r\n\r\nFor development:\r\n```bash\r\npip install vera-syntaxis[dev]\r\n```\r\n\r\nFor GUI support:\r\n```bash\r\npip install vera-syntaxis[gui]\r\n```\r\n\r\n## Quick Start\r\n\r\n### Command Line\r\n\r\n```bash\r\n# Parse and analyze a project\r\nvera-syntaxis analyze /path/to/project\r\n\r\n# Parse only (for debugging)\r\nvera-syntaxis parse /path/to/project\r\n```\r\n\r\n### Python API\r\n\r\n```python\r\nfrom vera_syntaxis import run_analysis\r\n\r\nviolations = run_analysis(\"/path/to/project\")\r\nfor violation in violations:\r\n print(f\"{violation.file_path}:{violation.line_number} - {violation.message}\")\r\n```\r\n\r\n## Configuration\r\n\r\nCreate a `pyproject.toml` in your project root:\r\n\r\n```toml\r\n[tool.vera_syntaxis]\r\nmodel_paths = [\"my_app/models/\"]\r\nview_paths = [\"my_app/views/\"]\r\nbusiness_paths = [\"my_app/services/\"]\r\ncontroller_paths = [\"my_app/controllers/\"]\r\nmodule_filter = [\"my_app.*\"]\r\n\r\n[tool.vera_syntaxis.coupling]\r\nmax_inter_class_calls = 5\r\nmax_demeter_chain = 3\r\n\r\n[tool.vera_syntaxis.circular]\r\nallow_self_cycles = false\r\nmax_cycle_length = 10\r\n\r\n[tool.vera_syntaxis.god_object]\r\nmax_methods = 20\r\nmax_attributes = 15\r\nmax_lines = 300\r\n\r\n[tool.vera_syntaxis.feature_envy]\r\nenvy_threshold = 0.5\r\nmin_accesses = 3\r\n\r\n[tool.vera_syntaxis.data_clump]\r\nmin_clump_size = 3\r\nmin_occurrences = 2\r\n```\r\n\r\n## Architectural Rules\r\n\r\n### Tight Coupling Linter\r\n\r\n#### TC001: Direct Instantiation\r\nFlags direct class instantiations that create tight coupling.\r\n\r\n**Example Violation:**\r\n```python\r\nclass UserService:\r\n def create_user(self):\r\n # Bad: Direct instantiation creates tight coupling\r\n db = Database()\r\n return db.save(User())\r\n```\r\n\r\n**Fix:** Use dependency injection instead.\r\n\r\n#### TC002: Law of Demeter (Method Chaining)\r\nDetects excessive method chaining that violates the Law of Demeter.\r\n\r\n**Configuration:**\r\n- `max_demeter_chain`: Maximum allowed chain length (default: 5)\r\n\r\n**Example Violation:**\r\n```python\r\n# Bad: Chain length of 4 exceeds configured maximum of 3\r\ncountry = user.address.city.postal_code.country\r\n```\r\n\r\n**Fix:** Break the chain using intermediate variables or add helper methods:\r\n```python\r\n# Good: Use intermediate variables\r\naddress = user.address\r\ncity = address.city\r\npostal_code = city.postal_code\r\ncountry = postal_code.country\r\n\r\n# Or: Add a helper method\r\ncountry = user.get_country()\r\n```\r\n\r\n#### TC003: Excessive Interaction\r\nIdentifies classes with too many inter-class calls using call graph analysis.\r\n\r\n**Configuration:**\r\n- `max_inter_class_calls`: Maximum allowed unique method calls to other classes (default: 10)\r\n\r\n**Example Violation:**\r\n```python\r\nclass Client:\r\n def __init__(self):\r\n self.service_a = ServiceA()\r\n self.service_b = ServiceB()\r\n self.service_c = ServiceC()\r\n \r\n def do_work(self):\r\n # Bad: Calls 12 unique methods from other classes (exceeds limit of 10)\r\n self.service_a.method1()\r\n self.service_a.method2()\r\n self.service_a.method3()\r\n self.service_a.method4()\r\n self.service_b.method1()\r\n self.service_b.method2()\r\n self.service_b.method3()\r\n self.service_b.method4()\r\n self.service_c.method1()\r\n self.service_c.method2()\r\n self.service_c.method3()\r\n self.service_c.method4()\r\n```\r\n\r\n**Fix:** Refactor to reduce coupling:\r\n```python\r\n# Good: Introduce a facade or coordinator\r\nclass ServiceCoordinator:\r\n def __init__(self):\r\n self.service_a = ServiceA()\r\n self.service_b = ServiceB()\r\n self.service_c = ServiceC()\r\n \r\n def execute_workflow(self):\r\n # Encapsulates the complex interactions\r\n self.service_a.do_work()\r\n self.service_b.do_work()\r\n self.service_c.do_work()\r\n\r\nclass Client:\r\n def __init__(self):\r\n self.coordinator = ServiceCoordinator()\r\n \r\n def do_work(self):\r\n # Now only 1 inter-class call\r\n self.coordinator.execute_workflow()\r\n```\r\n\r\n### MVBC Linter\r\n\r\n#### W2902: Illegal Layer Dependency\r\nEnforces proper layer communication in Model-View-Business-Controller architecture.\r\n\r\n**Allowed Dependencies:**\r\n- **Model**: Can be used by anyone (no dependencies on other layers)\r\n- **View**: Can use Model only\r\n- **Business**: Can use Model only \r\n- **Controller**: Can use View, Business, and Model\r\n\r\n**Forbidden Dependencies:**\r\n- View \u2192 Business (must go through Controller)\r\n- Business \u2192 View (business logic shouldn't know about presentation)\r\n- View \u2192 Controller (creates circular dependency)\r\n- Business \u2192 Controller (creates circular dependency)\r\n\r\n**Configuration:**\r\nSupports both single-level and nested directory patterns:\r\n```toml\r\n[tool.vera_syntaxis.mvbc]\r\nmodel_paths = [\"models/*.py\"] # Matches models/user.py and models/subdir/user.py\r\nview_paths = [\"views/**/*.py\"] # Explicit nested pattern\r\nbusiness_paths = [\"business/*.py\"]\r\ncontroller_paths = [\"controllers/*.py\"]\r\n```\r\n\r\n**Example Violations:**\r\n\r\n*View \u2192 Business:*\r\n```python\r\n# In views/user_view.py\r\nfrom business.user_logic import UserLogic # Bad: View importing Business\r\n\r\nclass UserView:\r\n def __init__(self):\r\n self.logic = UserLogic()\r\n```\r\n**Fix:** Use a Controller to mediate between View and Business.\r\n\r\n*Business \u2192 View:*\r\n```python\r\n# In business/user_logic.py\r\nfrom views.user_view import UserView # Bad: Business importing View\r\n\r\nclass UserLogic:\r\n def __init__(self):\r\n self.view = UserView()\r\n```\r\n**Fix:** Keep business logic independent of presentation. Controllers should manage Views.\r\n\r\n### Circular Dependency Linter\r\n\r\n#### CD001: Circular Dependency\r\nDetects circular dependencies between modules.\r\n\r\n**Configuration:**\r\n- `allow_self_cycles`: Allow methods to call themselves (default: false)\r\n- `max_cycle_length`: Maximum cycle length to report (default: 10)\r\n\r\n**Example Violation:**\r\n```python\r\n# module_a.py\r\nfrom module_b import ClassB\r\n\r\nclass ClassA:\r\n def method(self):\r\n b = ClassB()\r\n\r\n# module_b.py\r\nfrom module_a import ClassA # Circular dependency!\r\n\r\nclass ClassB:\r\n def method(self):\r\n a = ClassA()\r\n```\r\n\r\n**Fix:** Break the cycle using dependency inversion:\r\n```python\r\n# interface.py\r\nfrom abc import ABC, abstractmethod\r\n\r\nclass IProcessor(ABC):\r\n @abstractmethod\r\n def process(self): pass\r\n\r\n# module_a.py\r\nfrom interface import IProcessor\r\n\r\nclass ClassA(IProcessor):\r\n def process(self):\r\n pass\r\n\r\n# module_b.py\r\nfrom interface import IProcessor\r\n\r\nclass ClassB:\r\n def __init__(self, processor: IProcessor):\r\n self.processor = processor\r\n```\r\n\r\n### God Object Linter\r\n\r\n#### GO001: God Object\r\nDetects classes with too many responsibilities (God Objects).\r\n\r\n**Configuration:**\r\n- `max_methods`: Maximum number of methods allowed (default: 20)\r\n- `max_attributes`: Maximum number of attributes allowed (default: 15)\r\n- `max_lines`: Maximum number of lines allowed (default: 300)\r\n\r\n**Example Violation:**\r\n```python\r\nclass UserManager: # God Object!\r\n def __init__(self):\r\n self.db = Database()\r\n self.cache = Cache()\r\n self.logger = Logger()\r\n self.validator = Validator()\r\n self.emailer = Emailer()\r\n # ... 15+ attributes\r\n \r\n def create_user(self): pass\r\n def update_user(self): pass\r\n def delete_user(self): pass\r\n def validate_email(self): pass\r\n def send_welcome_email(self): pass\r\n def log_activity(self): pass\r\n # ... 20+ methods\r\n```\r\n\r\n**Fix:** Split into focused classes:\r\n```python\r\n# Separate concerns into focused classes\r\nclass UserRepository:\r\n def __init__(self, db):\r\n self.db = db\r\n \r\n def create(self, user): pass\r\n def update(self, user): pass\r\n def delete(self, user_id): pass\r\n\r\nclass UserValidator:\r\n def validate_email(self, email): pass\r\n def validate_password(self, password): pass\r\n\r\nclass UserNotifier:\r\n def __init__(self, emailer):\r\n self.emailer = emailer\r\n \r\n def send_welcome_email(self, user): pass\r\n def send_password_reset(self, user): pass\r\n\r\nclass UserService:\r\n def __init__(self, repo, validator, notifier):\r\n self.repo = repo\r\n self.validator = validator\r\n self.notifier = notifier\r\n \r\n def create_user(self, user_data):\r\n if self.validator.validate_email(user_data['email']):\r\n user = self.repo.create(user_data)\r\n self.notifier.send_welcome_email(user)\r\n return user\r\n```\r\n\r\n### Feature Envy Linter\r\n\r\n#### FE001: Feature Envy\r\nDetects methods that use more features from another class than their own.\r\n\r\n**Configuration:**\r\n- `envy_threshold`: Ratio of external to total accesses that triggers envy (default: 0.5)\r\n- `min_accesses`: Minimum total accesses before checking (default: 3)\r\n\r\n**Example Violation:**\r\n```python\r\nclass Order:\r\n def __init__(self):\r\n self.customer = Customer()\r\n \r\n def validate_customer_email(self): # Feature Envy!\r\n # Uses customer features more than own features\r\n email = self.customer.email\r\n email = self.customer.email.strip()\r\n email = self.customer.email.lower()\r\n is_valid = '@' in self.customer.email\r\n return is_valid\r\n```\r\n\r\n**Fix:** Move the method to the appropriate class:\r\n```python\r\nclass Customer:\r\n def __init__(self):\r\n self.email = \"\"\r\n \r\n def validate_email(self):\r\n # Now uses own features\r\n email = self.email.strip().lower()\r\n return '@' in email\r\n\r\nclass Order:\r\n def __init__(self):\r\n self.customer = Customer()\r\n \r\n def process(self):\r\n # Delegate to the appropriate class\r\n if self.customer.validate_email():\r\n # Process order\r\n pass\r\n```\r\n\r\n### Data Clump Linter\r\n\r\n#### DC001: Data Clump\r\nDetects groups of parameters that frequently appear together.\r\n\r\n**Configuration:**\r\n- `min_clump_size`: Minimum number of parameters in a clump (default: 3)\r\n- `min_occurrences`: Minimum number of methods with the clump (default: 2)\r\n\r\n**Example Violation:**\r\n```python\r\nclass OrderProcessor:\r\n def calculate_total(self, price, quantity, discount): # Data Clump!\r\n return price * quantity * (1 - discount)\r\n \r\n def validate_order(self, price, quantity, discount): # Same parameters\r\n return price > 0 and quantity > 0\r\n \r\n def format_order(self, price, quantity, discount): # Same parameters\r\n return f\"{quantity} items at ${price}\"\r\n```\r\n\r\n**Fix:** Extract data clump into a class:\r\n```python\r\nclass OrderDetails:\r\n def __init__(self, price: float, quantity: int, discount: float):\r\n self.price = price\r\n self.quantity = quantity\r\n self.discount = discount\r\n \r\n def calculate_total(self) -> float:\r\n return self.price * self.quantity * (1 - self.discount)\r\n \r\n def validate(self) -> bool:\r\n return self.price > 0 and self.quantity > 0\r\n \r\n def format(self) -> str:\r\n return f\"{self.quantity} items at ${self.price}\"\r\n\r\nclass OrderProcessor:\r\n def process_order(self, details: OrderDetails):\r\n if details.validate():\r\n total = details.calculate_total()\r\n print(details.format())\r\n return total\r\n```\r\n\r\n## Limitations\r\n\r\n- Requires extensive type hints for accurate analysis\r\n- Dynamic attributes (via `__getattr__`) may not be detected\r\n- Forward references must be properly annotated\r\n\r\n## Development Status\r\n\r\nVersion 0.1.0 - Alpha (Reporting Only)\r\n\r\n## License\r\n\r\nMIT License\r\n\r\n## Contributing\r\n\r\nContributions welcome! Please see CONTRIBUTING.md for guidelines.\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A static analysis tool for detecting architectural code smells in Python",
"version": "0.1.0",
"project_urls": {
"Bug Tracker": "https://github.com/yourusername/vera-syntaxis/issues",
"Homepage": "https://github.com/yourusername/vera-syntaxis"
},
"split_keywords": [
"linter",
" architecture",
" code-quality",
" static-analysis",
" design-patterns"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "233d549f7989e8d807a9cf5abbbbff7cba2e76efdefb22899e1c16f966a2755a",
"md5": "3c8c67255b04b24f3850fd32466896d6",
"sha256": "f4b656399e50f18e68cea43b487fd6971ff9a6f8fd94860f1298775454817e19"
},
"downloads": -1,
"filename": "vera_syntaxis-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3c8c67255b04b24f3850fd32466896d6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 74682,
"upload_time": "2025-10-10T21:21:20",
"upload_time_iso_8601": "2025-10-10T21:21:20.231506Z",
"url": "https://files.pythonhosted.org/packages/23/3d/549f7989e8d807a9cf5abbbbff7cba2e76efdefb22899e1c16f966a2755a/vera_syntaxis-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "6d8958406268bb24e4b8c7befd1e2451f3263449c9a7cff5e75a734173baf4fb",
"md5": "2a0681a6d75d8bd75103aaa4edf7dd02",
"sha256": "aa2b25b8fbd67ccad8dfdc943f4e4efea6b8e3c41ca1601763128fc73e5aad8e"
},
"downloads": -1,
"filename": "vera_syntaxis-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "2a0681a6d75d8bd75103aaa4edf7dd02",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 78417,
"upload_time": "2025-10-10T21:21:21",
"upload_time_iso_8601": "2025-10-10T21:21:21.640158Z",
"url": "https://files.pythonhosted.org/packages/6d/89/58406268bb24e4b8c7befd1e2451f3263449c9a7cff5e75a734173baf4fb/vera_syntaxis-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-10 21:21:21",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "yourusername",
"github_project": "vera-syntaxis",
"github_not_found": true,
"lcname": "vera-syntaxis"
}