imports.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. """Import operations."""
  2. from __future__ import annotations
  3. from collections import defaultdict
  4. from typing import Dict, List, Optional, Union
  5. from reflex.base import Base
  6. def merge_imports(*imports: ImportDict | ParsedImportDict) -> ParsedImportDict:
  7. """Merge multiple import dicts together.
  8. Args:
  9. *imports: The list of import dicts to merge.
  10. Returns:
  11. The merged import dicts.
  12. """
  13. all_imports = defaultdict(list)
  14. for import_dict in imports:
  15. for lib, fields in import_dict.items():
  16. all_imports[lib].extend(fields)
  17. return all_imports
  18. def parse_imports(imports: ImportDict | ParsedImportDict) -> ParsedImportDict:
  19. """Parse the import dict into a standard format.
  20. Args:
  21. imports: The import dict to parse.
  22. Returns:
  23. The parsed import dict.
  24. """
  25. def _make_list(value: ImportTypes) -> list[str | ImportVar] | list[ImportVar]:
  26. if isinstance(value, (str, ImportVar)):
  27. return [value]
  28. return value
  29. return {
  30. package: [
  31. ImportVar(tag=tag) if isinstance(tag, str) else tag
  32. for tag in _make_list(maybe_tags)
  33. ]
  34. for package, maybe_tags in imports.items()
  35. }
  36. def collapse_imports(imports: ParsedImportDict) -> ParsedImportDict:
  37. """Remove all duplicate ImportVar within an ImportDict.
  38. Args:
  39. imports: The import dict to collapse.
  40. Returns:
  41. The collapsed import dict.
  42. """
  43. return {
  44. lib: list(set(import_vars)) if isinstance(import_vars, list) else import_vars
  45. for lib, import_vars in imports.items()
  46. }
  47. class ImportVar(Base):
  48. """An import var."""
  49. # The name of the import tag.
  50. tag: Optional[str]
  51. # whether the import is default or named.
  52. is_default: Optional[bool] = False
  53. # The tag alias.
  54. alias: Optional[str] = None
  55. # Whether this import need to install the associated lib
  56. install: Optional[bool] = True
  57. # whether this import should be rendered or not
  58. render: Optional[bool] = True
  59. # whether this import package should be added to transpilePackages in next.config.js
  60. # https://nextjs.org/docs/app/api-reference/next-config-js/transpilePackages
  61. transpile: Optional[bool] = False
  62. @property
  63. def name(self) -> str:
  64. """The name of the import.
  65. Returns:
  66. The name(tag name with alias) of tag.
  67. """
  68. if self.alias:
  69. return (
  70. self.alias if self.is_default else " as ".join([self.tag, self.alias]) # type: ignore
  71. )
  72. else:
  73. return self.tag or ""
  74. def __hash__(self) -> int:
  75. """Define a hash function for the import var.
  76. Returns:
  77. The hash of the var.
  78. """
  79. return hash(
  80. (
  81. self.tag,
  82. self.is_default,
  83. self.alias,
  84. self.install,
  85. self.render,
  86. self.transpile,
  87. )
  88. )
  89. ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
  90. ImportDict = Dict[str, ImportTypes]
  91. ParsedImportDict = Dict[str, List[ImportVar]]