documentor.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import inspect
  2. import warnings
  3. from typing import Any, Dict, List, Optional, Tuple, Union
  4. from .generator import Generator
  5. from .providers import BaseProvider
  6. from .proxy import Faker
  7. class Documentor:
  8. def __init__(self, generator: Union[Generator, Faker]) -> None:
  9. """
  10. :param generator: a localized Generator with providers filled,
  11. for which to write the documentation
  12. :type generator: faker.Generator()
  13. """
  14. self.generator = generator
  15. self.max_name_len: int = 0
  16. self.already_generated: List[str] = []
  17. def get_formatters(
  18. self,
  19. locale: Optional[str] = None,
  20. excludes: Optional[List[str]] = None,
  21. **kwargs: Any,
  22. ) -> List[Tuple[BaseProvider, Dict[str, str]]]:
  23. self.max_name_len = 0
  24. self.already_generated = [] if excludes is None else excludes[:]
  25. formatters = []
  26. providers: List[BaseProvider] = self.generator.get_providers()
  27. for provider in providers[::-1]: # reverse
  28. if locale and provider.__lang__ != locale:
  29. continue
  30. formatters.append(
  31. (provider, self.get_provider_formatters(provider, **kwargs)),
  32. )
  33. return formatters
  34. def get_provider_formatters(
  35. self,
  36. provider: BaseProvider,
  37. prefix: str = "fake.",
  38. with_args: bool = True,
  39. with_defaults: bool = True,
  40. ) -> Dict[str, str]:
  41. formatters = {}
  42. for name, method in inspect.getmembers(provider, inspect.ismethod):
  43. # skip 'private' method and inherited methods
  44. if name.startswith("_") or name in self.already_generated:
  45. continue
  46. arguments = []
  47. faker_args: List[str] = []
  48. faker_kwargs = {}
  49. if name == "binary":
  50. faker_kwargs["length"] = 1024
  51. elif name in ["zip", "tar"]:
  52. faker_kwargs.update(
  53. {
  54. "uncompressed_size": 1024,
  55. "min_file_size": 512,
  56. }
  57. )
  58. if with_args:
  59. # retrieve all parameter
  60. argspec = inspect.getfullargspec(method)
  61. lst = [x for x in argspec.args if x not in ["self", "cls"]]
  62. for i, arg in enumerate(lst):
  63. if argspec.defaults and with_defaults:
  64. try:
  65. default = argspec.defaults[i]
  66. if isinstance(default, str):
  67. default = repr(default)
  68. else:
  69. # TODO check default type
  70. default = f"{default}"
  71. arg = f"{arg}={default}"
  72. except IndexError:
  73. pass
  74. arguments.append(arg)
  75. if with_args == "first":
  76. break
  77. if with_args != "first":
  78. if argspec.varargs:
  79. arguments.append("*" + argspec.varargs)
  80. if argspec.varkw:
  81. arguments.append("**" + argspec.varkw)
  82. # build fake method signature
  83. signature = f"{prefix}{name}({', '.join(arguments)})"
  84. try:
  85. # make a fake example
  86. example = self.generator.format(name, *faker_args, **faker_kwargs)
  87. except (AttributeError, ValueError) as e:
  88. warnings.warn(str(e))
  89. continue
  90. formatters[signature] = example
  91. self.max_name_len = max(self.max_name_len, len(signature))
  92. self.already_generated.append(name)
  93. return formatters
  94. @staticmethod
  95. def get_provider_name(provider_class: BaseProvider) -> str:
  96. return provider_class.__provider__