Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔀🔧 MERGE: Add strict typing for most sphinx_needs modules #1002

Merged
merged 29 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c9669d0
🔧 Add strict typing for `sphinx_needs.diagrams_common`
chrisjsewell Aug 28, 2023
ca029c2
🔧 Add strict typing for `sphinx_needs.warnings`
chrisjsewell Aug 28, 2023
99b88d5
🔧 Add strict typing for `sphinx_needs.environment`
chrisjsewell Aug 28, 2023
1bbf9db
🔧 Add strict typing for `sphinx_needs.needs`
chrisjsewell Aug 28, 2023
afbf32a
🔧 Add strict typing for `sphinx_needs.services.manager`
chrisjsewell Aug 28, 2023
e2b277c
🔧 Add strict typing for `sphinx_needs.directives.needgantt`
chrisjsewell Aug 28, 2023
e45bc1a
🔧 Add strict typing for `sphinx_needs.directives.needsequence`
chrisjsewell Aug 28, 2023
969363c
🔧 Add strict typing for `sphinx_needs.directives.needlist`
chrisjsewell Aug 28, 2023
f8c4d00
🔧 Add strict typing for `sphinx_needs.directives.needtable`
chrisjsewell Aug 28, 2023
741f565
🔧 Add strict typing for `sphinx_needs.roles.need_incoming`
chrisjsewell Aug 28, 2023
a19f4b0
🔧 Add strict typing for `sphinx_needs.roles.need_part`
chrisjsewell Aug 28, 2023
f3725a0
🔧 Add strict typing for `sphinx_needs.needsfile`
chrisjsewell Aug 28, 2023
2cd419f
🔧 Add strict typing for `sphinx_needs.functions.common`
chrisjsewell Aug 28, 2023
af63ab3
🔧 Add strict typing for `sphinx_needs.external_needs`
chrisjsewell Aug 28, 2023
6f5508f
🔧 Add strict typing for `sphinx_needs.filter_common`
chrisjsewell Aug 28, 2023
93d2376
🔧 Add strict typing for `sphinx_needs.services.github`
chrisjsewell Aug 28, 2023
d5818a4
🔧 Add strict typing for `sphinx_needs.directives.utils`
chrisjsewell Aug 28, 2023
e326131
🔧 Add strict typing for `sphinx_needs.directives.needfilter`
chrisjsewell Aug 28, 2023
2e65cdd
🔧 Add strict typing for `sphinx_needs.directives.needflow`
chrisjsewell Aug 28, 2023
a723f9d
🔧 Fix typing of `debug.measure_time`
chrisjsewell Aug 28, 2023
fb8fda9
🔧 Add strict typing for `sphinx_needs.roles.need_refs`
chrisjsewell Aug 28, 2023
9a2577d
🔧 Add strict typing for `sphinx_needs.directives.needpie`
chrisjsewell Aug 28, 2023
3c3445c
🔧 Disallow some Any constructs in typing
chrisjsewell Aug 28, 2023
96c7506
🔧 Add strict typing for `sphinx_needs.directives.needextend`
chrisjsewell Aug 28, 2023
4338c02
🔧 Add strict typing for `sphinx_needs.directives.needbar`
chrisjsewell Aug 28, 2023
8994677
🔧 Add strict typing for `sphinx_needs.data`
chrisjsewell Aug 28, 2023
ab5ea94
🔧 Add strict typing for `sphinx_needs.directives.need`
chrisjsewell Aug 28, 2023
ce9ac85
🔧 Add strict typing for `sphinx_needs.utils`
chrisjsewell Aug 29, 2023
146bc68
🔧 Add strict typing for `sphinx_needs.layout`
chrisjsewell Aug 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ repos:
additional_dependencies:
- sphinx==6
- types-docutils
- types-jsonschema
- types-requests

- repo: https://github.com/python-poetry/poetry
Expand Down
54 changes: 24 additions & 30 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,51 +86,45 @@ strict = true
show_error_codes = true
implicit_reexport = true
namespace_packages = true
disallow_any_generics = true
disallow_subclassing_any = true
# disallow_any_unimported = true
# disallow_any_explicit = true
# disallow_any_expr = true
# disallow_any_decorated = true

[[tool.mypy.overrides]]
module = [
"matplotlib.*",
"numpy.*",
"requests_file",
"sphinx_data_viewer.*"
"sphinx_data_viewer.*",
"sphinxcontrib.plantuml.*",
]
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = [
'sphinx_needs.api.need',
'sphinx_needs.data',
'sphinx_needs.diagrams_common',
'sphinx_needs.directives.need',
'sphinx_needs.directives.needbar',
'sphinx_needs.directives.needextend',
'sphinx_needs.directives.needextract',
'sphinx_needs.directives.needfilter',
'sphinx_needs.directives.needflow',
'sphinx_needs.directives.needgantt',
'sphinx_needs.directives.needlist',
'sphinx_needs.directives.needpie',
'sphinx_needs.directives.needsequence',
'sphinx_needs.directives.needtable',
'sphinx_needs.directives.needuml',
'sphinx_needs.directives.utils',
'sphinx_needs.environment',
'sphinx_needs.external_needs',
'sphinx_needs.filter_common',
'sphinx_needs.functions.common',
'sphinx_needs.functions.functions',
'sphinx_needs.layout',
'sphinx_needs.needs',
'sphinx_needs.needsfile',
'sphinx_needs.roles.need_incoming',
'sphinx_needs.roles.need_outgoing',
'sphinx_needs.roles.need_part',
'sphinx_needs.roles.need_ref',
'sphinx_needs.services.github',
'sphinx_needs.services.manager',
'sphinx_needs.utils',
'sphinx_needs.warnings',
]
ignore_errors = true

[[tool.mypy.overrides]]
module = [
"sphinx_needs.directives.needextend"
]
# TODO dynamically overriding TypeDict keys is a bit tricky
disable_error_code = "literal-required"

[[tool.mypy.overrides]]
module = [
"sphinx_needs.data"
]
disable_error_code = ["attr-defined", "no-any-return"]


[build-system]
requires = ["setuptools", "poetry_core>=1.0.8"] # setuptools for deps like plantuml
build-backend = "poetry.core.masonry.api"
Expand Down
1 change: 0 additions & 1 deletion sphinx_needs/api/need.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,6 @@ def run():
"docname": docname,
"doctype": doctype,
"lineno": lineno,
# "target_node": target_node,
"target_id": need_id,
"external_url": external_url,
"content_node": None, # gets set after rst parsing
Expand Down
7 changes: 3 additions & 4 deletions sphinx_needs/builder.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import os
from typing import Iterable, Optional, Set
from typing import Iterable, List, Optional, Set

from docutils import nodes
from sphinx import version_info
from sphinx.application import Sphinx
from sphinx.builders import Builder

from sphinx_needs.config import NeedsSphinxConfig
from sphinx_needs.data import SphinxNeedsData
from sphinx_needs.data import NeedsInfoType, SphinxNeedsData
from sphinx_needs.logging import get_logger
from sphinx_needs.needsfile import NeedsList
from sphinx_needs.utils import unwrap
Expand All @@ -27,7 +27,6 @@ def write_doc(self, docname: str, doctree: nodes.document) -> None:
def finish(self) -> None:
env = unwrap(self.env)
data = SphinxNeedsData(env)
needs = data.get_or_create_needs().values() # We need a list of needs for later filter checks
filters = data.get_or_create_filters()
version = getattr(env.config, "version", "unset")
needs_list = NeedsList(env.config, self.outdir, self.srcdir)
Expand All @@ -50,7 +49,7 @@ def finish(self) -> None:
from sphinx_needs.filter_common import filter_needs

filter_string = needs_config.builder_filter
filtered_needs = filter_needs(self.app, needs, filter_string)
filtered_needs: List[NeedsInfoType] = filter_needs(self.app, data.get_or_create_needs().values(), filter_string)

for need in filtered_needs:
needs_list.add_need(version, need)
Expand Down
4 changes: 2 additions & 2 deletions sphinx_needs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def __setattr__(self, name: str, value: Any) -> None:
default=DEFAULT_DIAGRAM_TEMPLATE,
metadata={"rebuild": "html", "types": (str,)},
)
functions: list[Any] = field(default_factory=list, metadata={"rebuild": "html", "types": (list,)})
functions: list[Callable[..., Any]] = field(default_factory=list, metadata={"rebuild": "html", "types": (list,)})
global_options: dict[str, Any] = field(default_factory=dict, metadata={"rebuild": "html", "types": (dict,)})
duration_option: str = field(default="duration", metadata={"rebuild": "html", "types": (str,)})
completion_option: str = field(default="completion", metadata={"rebuild": "html", "types": (str,)})
Expand All @@ -171,7 +171,7 @@ def __setattr__(self, name: str, value: Any) -> None:
extra_links: list[dict[str, Any]] = field(default_factory=list, metadata={"rebuild": "html", "types": ()})
"""List of additional links, which can be used by setting related option
Values needed for each new link:
* name (will also be the option name)
* option (will also be the option name)
* incoming
* copy_link (copy to common links data. Default: True)
* color (used for needflow. Default: #000000)
Expand Down
67 changes: 35 additions & 32 deletions sphinx_needs/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"""
from __future__ import annotations

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

try:
from typing import Literal, TypedDict
except ImportError:
# introduced in python 3.8
from typing_extensions import Literal, TypedDict
from typing_extensions import Literal, TypedDict # type: ignore

if TYPE_CHECKING:
from docutils.nodes import Element, Text
Expand Down Expand Up @@ -63,18 +63,17 @@ class NeedsPartType(TypedDict):
id: str
"""ID of the part"""

# TODO are these necessary? i.e. its always a part, not a need
is_part: bool
is_need: bool

content: str
"""Content of the part."""
document: str
"""docname where the part is defined."""
links_back: list[str]
"""List of need IDs, which are referencing this part."""
links: list[str]
"""List of need IDs, which are referenced by this part."""
links_back: list[str]
"""List of need IDs, which are referencing this part."""


class NeedsInfoType(NeedsBaseDataType):
Expand Down Expand Up @@ -129,7 +128,6 @@ class NeedsInfoType(NeedsBaseDataType):

# parts information
parts: dict[str, NeedsPartType]
# TODO are these necessary? i.e. its always a need, not a part
is_need: bool
is_part: bool

Expand All @@ -149,17 +147,21 @@ class NeedsInfoType(NeedsBaseDataType):
# link information
links: list[str]
"""List of need IDs, which are referenced by this need."""
# TODO there is a lot more dynamically added link information;
# for each item in needs_extra_links config,
links_back: list[str]
"""List of need IDs, which are referencing this need."""
# TODO there is more dynamically added link information;
# for each item in needs_extra_links config
# (and in prepare_env 'links' and 'parent_needs' are added if not present),
# you end up with a key named by the "option" field,
# and then another key named by the "option" field + "_back"
# these all have value type `list[str]`
# back links are all set in process_need_nodes (-> create_back_links) transform

# constraints information
# set in process_need_nodes (-> process_constraints) transform
constraints: list[str]
constraints_passed: None | bool
constraints_results: dict[str, dict[str, bool]]
constraints_results: dict[str, dict[str, Any]]

# additional source information
doctype: str
Expand All @@ -171,8 +173,15 @@ class NeedsInfoType(NeedsBaseDataType):
signature: str | Text
"""Derived from a docutils desc_name node"""
parent_needs: list[str]
"""List of parents of the this need (by id),
i.e. if this need is nested in another
"""
parent_needs_back: list[str]
"""List of children of this need (by id),
i.e. if needs are nested within this one
"""
parent_need: str
"""Simply the first parent"""
"""Simply the first parent id"""

# default extra options
# TODO these all default to "" which I don't think is good
Expand All @@ -192,7 +201,7 @@ class NeedsInfoType(NeedsBaseDataType):
max_amount: str
service: str
specific: str
type: str
# _type: str # type is already set in create_need
updated_at: str
user: str
# OpenNeedsService
Expand All @@ -210,6 +219,15 @@ class NeedsInfoType(NeedsBaseDataType):
# - dynamic global options that can be set by needs_global_options config


class NeedsPartsInfoType(NeedsInfoType):
"""Generated by prepare_need_list"""

document: str
"""docname where the part is defined."""
id_parent: str
id_complete: str


class NeedsBarType(NeedsBaseDataType):
"""Data for a single (matplotlib) bar diagram."""

Expand All @@ -225,9 +243,9 @@ class NeedsBarType(NeedsBaseDataType):
ylabels_rotation: str
separator: str
stacked: bool
show_sum: bool
show_top_sum: bool
sum_rotation: bool
show_sum: None | bool
show_top_sum: None | bool
sum_rotation: None | str
transpose: bool
horizontal: bool
style: str
Expand All @@ -246,13 +264,12 @@ class NeedsExtendType(NeedsBaseDataType):
class NeedsFilteredBaseType(NeedsBaseDataType):
"""A base type for all filtered data."""

# Filter attributes
status: list[str]
tags: list[str]
types: list[str]
filter: None | str
sort_by: None | str
filter_code: str
filter_code: list[str]
filter_func: None | str
export_id: str

Expand All @@ -276,7 +293,6 @@ class NeedsFilteredDiagramBaseType(NeedsFilteredBaseType):
class NeedsExtractType(NeedsFilteredBaseType):
"""Data to extract needs from a document."""

export_id: str
layout: str
style: str
show_filters: bool
Expand All @@ -294,24 +310,11 @@ class _NeedsFilterType(NeedsFilteredBaseType):
show_filters: bool
show_legend: bool
layout: Literal["list", "table", "diagram"]
export_id: str


class NeedsFlowType(NeedsFilteredDiagramBaseType):
"""Data for a single (filtered) flow chart."""

caption: None | str
show_filters: bool
show_legend: bool
show_link_names: bool
debug: bool
config_names: str
config: str
scale: str
highlight: str
align: str
link_types: list[str]


class NeedsGanttType(NeedsFilteredDiagramBaseType):
"""Data for a single (filtered) gantt chart."""
Expand All @@ -333,7 +336,6 @@ class NeedsListType(NeedsFilteredBaseType):
show_tags: bool
show_status: bool
show_filters: bool
export_id: str


class NeedsPieType(NeedsBaseDataType):
Expand Down Expand Up @@ -363,6 +365,7 @@ class NeedsTableType(NeedsFilteredBaseType):
caption: None | str
classes: list[str]
columns: list[tuple[str, str]]
"""List of (name, title)"""
colwidths: list[int]
style: str
style_row: str
Expand Down Expand Up @@ -449,7 +452,7 @@ def get_or_create_workflow(self) -> NeedsWorkflowType:
for link_type in self.env.app.config.needs_extra_links:
self.env.needs_workflow["backlink_creation_{}".format(link_type["option"])] = False

return self.env.needs_workflow
return self.env.needs_workflow # type: ignore[return-value]

def get_or_create_services(self) -> ServiceManager:
"""Get information about services.
Expand Down
Loading