Skip to content

Commit

Permalink
[cdd/compound/exmod_utils.py] Properly determine the fully-qualified …
Browse files Browse the repository at this point in the history
…module name to import from ; [cdd/compound/exmod.py] Pass around `first_output_directory` ; [cdd/shared/ast_utils.py] Deduplicate `infer_imports` out of `from` elements ; [README.md] Add (temporary) hack instructions
  • Loading branch information
SamuelMarks committed Feb 11, 2024
1 parent 0c6b616 commit 18aa8ec
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 46 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,12 @@ PS: If you want to `import` every module, e.g., for your `create_tables` script

python -c 'import os;fast_scandir = lambda dirname: [f.path for f in os.scandir(dirname) if f.is_dir()] + [item for sublist in [fast_scandir(d) for d in [f.path for f in os.scandir(dirname) if f.is_dir()]] for item in sublist];print("\n".join(sorted(frozenset(map(lambda m: "import {}.{}".format(os.path.basename(os.path.abspath(".")), m.replace(os.path.sep, ".")[2:]),fast_scandir("."))))))'

PPS: Below is a temporary hack to run on the SQLalchemy output to make it work; until the `tuple`|`Tuple`|`List`|`list`|`name` as column-type bug is resolved:

fastmod --accept-all -iF 'tuple, comment=' 'LargeBinary, comment=' ; fastmod --accept-all -iF 'tuple,
comment=' 'LargeBinary, comment=' ; fastmod --accept-all -iF 'list, comment=' 'LargeBinary, comment=' ; fastmod --accept-all -iF 'list,
comment=' 'LargeBinary, comment=' ; fastmod --accept-all -iF 'name, comment=' 'String, comment='

---

## License
Expand Down
2 changes: 1 addition & 1 deletion cdd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from logging import getLogger as get_logger

__author__ = "Samuel Marks" # type: str
__version__ = "0.0.99rc27" # type: str
__version__ = "0.0.99rc28" # type: str
__description__ = (
"Open API to/fro routes, models, and tests. "
"Convert between docstrings, classes, methods, argparse, pydantic, and SQLalchemy."
Expand Down
6 changes: 6 additions & 0 deletions cdd/compound/exmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def exmod(
new_module_name=new_module_name,
filesystem_layout=filesystem_layout,
extra_modules_to_all=extra_modules_to_all,
first_output_directory=output_directory,
)
packages: typing.List[str] = find_packages(
module_root_dir,
Expand Down Expand Up @@ -309,6 +310,7 @@ def exmod_single_folder(
blacklist,
whitelist,
output_directory,
first_output_directory,
mock_imports,
no_word_wrap,
dry_run,
Expand Down Expand Up @@ -338,6 +340,9 @@ def exmod_single_folder(
:param output_directory: Where to place the generated exposed interfaces to the given `--module`.
:type output_directory: ```str```
:param first_output_directory: Initial output directory (e.g., direct from `--output-directory`)
:type first_output_directory: ```str```
:param mock_imports: Whether to generate mock TensorFlow imports
:type mock_imports: ```bool```
Expand Down Expand Up @@ -387,6 +392,7 @@ def exmod_single_folder(
new_module_name=new_module_name,
emit_name=emit_name,
output_directory=output_directory,
first_output_directory=first_output_directory,
mock_imports=mock_imports,
no_word_wrap=no_word_wrap,
dry_run=dry_run,
Expand Down
47 changes: 32 additions & 15 deletions cdd/compound/exmod_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ def emit_file_on_hierarchy(
filesystem_layout,
extra_modules_to_all,
output_directory,
first_output_directory,
no_word_wrap,
dry_run,
):
Expand Down Expand Up @@ -232,6 +233,9 @@ def emit_file_on_hierarchy(
:param output_directory: Where to place the generated exposed interfaces to the given `--module`.
:type output_directory: ```str```
:param first_output_directory: Initial output directory (e.g., direct from `--output-directory`)
:type first_output_directory: ```str```
:param no_word_wrap: Whether word-wrap is disabled (on emission).
:type no_word_wrap: ```Optional[Literal[True]]```
Expand Down Expand Up @@ -344,19 +348,20 @@ def emit_file_on_hierarchy(

if not symbol_in_file and (ir.get("name") or ir["params"] or ir["returns"]):
_emit_symbol(
name_orig_ir,
emit_name,
module_name,
emit_filename,
existent_mod,
init_filepath,
ir,
isfile_emit_filename,
name,
mock_imports,
extra_modules_to_all,
no_word_wrap,
dry_run,
name_orig_ir=name_orig_ir,
emit_name=emit_name,
module_name=module_name,
emit_filename=emit_filename,
existent_mod=existent_mod,
init_filepath=init_filepath,
intermediate_repr=ir,
isfile_emit_filename=isfile_emit_filename,
name=name,
mock_imports=mock_imports,
extra_modules_to_all=extra_modules_to_all,
no_word_wrap=no_word_wrap,
first_output_directory=first_output_directory,
dry_run=dry_run,
)

# return (
Expand Down Expand Up @@ -391,6 +396,7 @@ def _emit_symbol(
mock_imports,
extra_modules_to_all,
no_word_wrap,
first_output_directory,
dry_run,
):
"""
Expand Down Expand Up @@ -441,6 +447,9 @@ def _emit_symbol(
:param no_word_wrap: Whether word-wrap is disabled (on emission).
:type no_word_wrap: ```Optional[Literal[True]]```
:param first_output_directory: Where to place the generated exposed interfaces to the given `--module`.
:type first_output_directory: ```str```
:param dry_run: Show what would be created; don't actually write to the filesystem
:type dry_run: ```bool```
Expand Down Expand Up @@ -561,6 +570,9 @@ def _emit_symbol(
file=EXMOD_OUT_STREAM,
)
else:
module = path.splitext(
emit_filename[len(path.dirname(first_output_directory)) + 1 :]
)[0].replace(path.sep, ".")
cdd.shared.emit.file.file(
Module(
body=[
Expand All @@ -572,7 +584,7 @@ def _emit_symbol(
col_offset=None,
),
ImportFrom(
module=path.splitext(path.basename(emit_filename))[0],
module=module,
names=[
alias(
name=name,
Expand All @@ -581,7 +593,7 @@ def _emit_symbol(
identifier_name=None,
),
],
level=1,
level=0,
identifier=None,
),
__all___node,
Expand All @@ -601,6 +613,7 @@ def emit_files_from_module_and_return_imports(
emit_name,
module,
output_directory,
first_output_directory,
mock_imports,
no_word_wrap,
dry_run,
Expand Down Expand Up @@ -630,6 +643,9 @@ def emit_files_from_module_and_return_imports(
:param output_directory: Where to place the generated exposed interfaces to the given `--module`.
:type output_directory: ```str```
:param first_output_directory: Initial output directory (e.g., direct from `--output-directory`)
:type first_output_directory: ```str```
:param mock_imports: Whether to generate mock TensorFlow imports
:type mock_imports: ```bool```
Expand All @@ -656,6 +672,7 @@ def emit_files_from_module_and_return_imports(
mock_imports=mock_imports,
filesystem_layout=filesystem_layout,
output_directory=output_directory,
first_output_directory=first_output_directory,
extra_modules_to_all=extra_modules_to_all,
no_word_wrap=no_word_wrap,
dry_run=dry_run,
Expand Down
2 changes: 1 addition & 1 deletion cdd/shared/ast_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2277,7 +2277,7 @@ def node_to_importable_name(node):
identifier=None,
identifier_name=None,
),
map(itemgetter(0), mod_names[1]),
sorted(frozenset(map(itemgetter(0), mod_names[1]))),
),
),
level=0,
Expand Down
85 changes: 56 additions & 29 deletions cdd/sqlalchemy/utils/emit_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,34 +84,11 @@ def param_to_sqlalchemy_column_calls(name_param, include_name):
name, _param = name_param
del name_param

args, keywords, nullable, multiple = [], [], None, False
args, keywords, nullable = [], [], None

if include_name:
args.append(cdd.shared.ast_utils.set_value(name))

x_typ_sql = _param.get("x_typ", {}).get("sql", {}) # type: dict

if "typ" in _param:
(
nullable,
multiple,
) = cdd.sqlalchemy.utils.shared_utils.update_args_infer_typ_sqlalchemy(
_param, args, name, nullable, x_typ_sql
)

if len(args) < 2 and (
not args
or not (
isinstance(args[0], Name) and args[0].id in sqlalchemy_top_level_imports
)
and not (
isinstance(args[0], Call)
and isinstance(args[0].func, Name)
and args[0].func.id in sqlalchemy_top_level_imports
)
):
# A good default I guess?
args.append(Name("LargeBinary", Load(), lineno=None, col_offset=None))
nullable, x_typ_sql = _handle_column_args(
_param, args, include_name, name, nullable
)

default = x_typ_sql.get("default", _param.get("default", ast))
has_default: bool = default is not ast
Expand Down Expand Up @@ -145,6 +122,7 @@ def param_to_sqlalchemy_column_calls(name_param, include_name):
keywords = _handle_column_keywords(
_param, default, has_default, keywords, nullable, x_typ_sql
)

# elif _param["doc"]:
# keywords.append(
# ast.keyword(arg="comment", value=set_value(_param["doc"]), identifier=None)
Expand Down Expand Up @@ -174,11 +152,60 @@ def param_to_sqlalchemy_column_calls(name_param, include_name):
)


def _handle_column_args(_param, args, include_name, name, nullable):
"""
Populate non-keyword args for the `Column(…)`. Internal function.
:param _param: dict with keys: 'typ', 'doc', 'default'
:type _param: ```dict```
:param args: holds a list of the arguments passed by position
:type args: ```List[AST]```
:param include_name: Whether to include the name (exclude in declarative base)
:type include_name: ```bool```
:param name: Parameter name
:type name: ```str```
:param nullable: Whether it is NULL-able
:type nullable: ```Optional[bool]```
:return: nullable, x_typ_sql
:rtype: ```Tuple[Optional[bool], dict]```
"""
if include_name:
args.append(cdd.shared.ast_utils.set_value(name))
x_typ_sql = _param.get("x_typ", {}).get("sql", {}) # type: dict
if "typ" in _param:
(
nullable,
multiple,
) = cdd.sqlalchemy.utils.shared_utils.update_args_infer_typ_sqlalchemy(
_param, args, name, nullable, x_typ_sql
)
if len(args) < 2 and (
not args
or not (
isinstance(args[0], Name) and args[0].id in sqlalchemy_top_level_imports
)
and not (
isinstance(args[0], Call)
and isinstance(args[0].func, Name)
and args[0].func.id in sqlalchemy_top_level_imports
)
):
# A good default I guess?
args.append(Name("LargeBinary", Load(), lineno=None, col_offset=None))

return nullable, x_typ_sql


def _handle_column_keywords(
_param, default, has_default, keywords, nullable, x_typ_sql
):
"""
Popular keyword args for the `Column(…)`. Internal function.
Populate keyword args for the `Column(…)`. Internal function.
:param _param: dict with keys: 'typ', 'doc', 'default'
:type _param: ```dict```
Expand All @@ -189,7 +216,7 @@ def _handle_column_keywords(
:param has_default: Whether it had a default value originally
:type has_default: ```bool`
:param keywords: Keywords list
:param keywords: holds a list of keyword objects representing arguments passed by keyword.
:type keywords: ```List[ast.keywords]```
:param nullable: Whether it is NULL-able
Expand Down
3 changes: 3 additions & 0 deletions cdd/tests/test_compound/test_exmod_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def test_emit_file_on_hierarchy_dry_run(self) -> None:
filesystem_layout=None,
extra_modules_to_all=None,
output_directory="",
first_output_directory="",
no_word_wrap=None,
dry_run=True,
)
Expand Down Expand Up @@ -65,6 +66,7 @@ def test_emit_file_on_hierarchy(self) -> None:
True,
filesystem_layout="as_input",
output_directory=tempdir,
first_output_directory=tempdir,
no_word_wrap=None,
dry_run=False,
extra_modules_to_all=None,
Expand Down Expand Up @@ -101,6 +103,7 @@ def test__emit_symbols_isfile_emit_filename_true(self) -> None:
mock_imports=True,
extra_modules_to_all=None,
no_word_wrap=None,
first_output_directory=path.join("foo", "module_name"),
dry_run=True,
)
func__merge_modules.assert_called_once()
Expand Down

0 comments on commit 18aa8ec

Please sign in to comment.