Repository: feast-dev/feast

Issue:
Failure when there is a hyphen in project names
## Expected Behavior 

Able to run `feast apply` when there is a hyphen in the project name

## Current Behavior

```
Registered entity year_month_day
Registered feature view serve_weather_features
Deploying infrastructure for serve_weather_features
Traceback (most recent call last):
  File "/home/willem/.pyenv/versions/3.7.7/bin/feast", line 33, in <module>
    sys.exit(load_entry_point('feast', 'console_scripts', 'feast')())
  File "/home/willem/.pyenv/versions/3.7.7/lib/python3.7/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/willem/.pyenv/versions/3.7.7/lib/python3.7/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/willem/.pyenv/versions/3.7.7/lib/python3.7/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/willem/.pyenv/versions/3.7.7/lib/python3.7/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/willem/.pyenv/versions/3.7.7/lib/python3.7/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/willem/Projects/feast/sdk/python/feast/cli.py", line 163, in apply_total_command
    apply_total(repo_config, Path.cwd())
  File "/home/willem/Projects/feast/sdk/python/feast/repo_operations.py", line 208, in apply_total
    partial=False,
  File "/home/willem/Projects/feast/sdk/python/feast/infra/local.py", line 61, in update_infra
    f"CREATE TABLE IF NOT EXISTS {_table_id(project, table)} (entity_key BLOB, feature_name TEXT, value BLOB, event_ts timestamp, created_ts timestamp,  PRIMARY KEY(entity_key, feature_name))"
sqlite3.OperationalError: near "-": syntax error
```

## Steps to reproduce

Clone https://github.com/dmatrix/mlflow-tests/tree/master/py/delta-lake
Run `feast apply` 

### Specifications

- Version: 0.10.3

## Possible Solution

The problem is that we don't support hyphens in project names. We should either prevent the use of hyphens or support them at the storage layer.


Discussion:
@woop As you know, SQLite disallows "-" in a table name.  For example:

```
sqlite3 bug.db 'create table-with-dash" ("col" text)'
Error: near "-": syntax error
```

SQLite does not support this at the storage layer, albeit creates the "bug.db" database without a table.

Since the `feast apply` uses the `project:<name>` table from the `feature_store.yaml`, created by `feast init <name>`, does it make sense to parse the <name> argument to the `feast init <name>` and flag an error,  disallowing its usage?

Preventing the use of "-" might be an easier workaround early on, during initializing a feast repo, unless you want to support “-“ at both local and remote storage layers. 

WDYT?

> @woop As you know, SQLite disallows "-" in a table name. For example:
> 
> ```
> sqlite3 bug.db 'create table-with-dash" ("col" text)'
> Error: near "-": syntax error
> ```
> 
> SQLite does not support this at the storage layer, albeit creates the "bug.db" database without a table.
> 
> Since the `feast apply` uses the `project:<name>` table from the `feature_store.yaml`, created by `feast init <name>`, does it make sense to parse the argument to the `feast init <name>` and flag an error, disallowing its usage?
> 
> Preventing the use of "-" might be an easier workaround early on, during initializing a feast repo, unless you want to support “-“ at both local and remote storage layers.
> 
> WDYT?

Spot on. It may be easiest to just allow alphanumeric values and underscores in project names as a start. As you say, validation would have to happen during init and also during apply. 

Resolving patch:
diff --git a/sdk/python/feast/repo_operations.py b/sdk/python/feast/repo_operations.py
--- a/sdk/python/feast/repo_operations.py
+++ b/sdk/python/feast/repo_operations.py
@@ -1,6 +1,7 @@
 import importlib
 import os
 import random
+import re
 import sys
 from datetime import timedelta
 from importlib.abc import Loader
@@ -8,6 +9,7 @@
 from typing import List, NamedTuple, Set, Union
 
 import click
+from click.exceptions import BadParameter
 
 from feast import Entity, FeatureTable
 from feast.feature_view import FeatureView
@@ -110,6 +112,12 @@ def apply_total(repo_config: RepoConfig, repo_path: Path):
     sys.path.append("")
     registry_config = repo_config.get_registry_config()
     project = repo_config.project
+    if not_valid_name(project):
+        print(
+            f"{project} is not valid. Project name should only have "
+            f"alphanumerical values and underscores."
+        )
+        sys.exit(1)
     registry = Registry(
         registry_path=registry_config.path,
         repo_path=repo_path,
@@ -262,6 +270,11 @@ def init_repo(repo_name: str, template: str):
 
     from colorama import Fore, Style
 
+    if not_valid_name(repo_name):
+        raise BadParameter(
+            message="Name should be alphanumeric values and underscores",
+            param_hint="PROJECT_DIRECTORY",
+        )
     repo_path = Path(os.path.join(Path.cwd(), repo_name))
     repo_path.mkdir(exist_ok=True)
     repo_config_path = repo_path / "feature_store.yaml"
@@ -314,6 +327,11 @@ def init_repo(repo_name: str, template: str):
     click.echo()
 
 
+def not_valid_name(name: str) -> bool:
+    """Test project or repo names. True if names have characters other than alphanumeric values and underscores"""
+    return re.compile(r"\W+").search(name) is not None
+
+
 def replace_str_in_file(file_path, match_str, sub_str):
     with open(file_path, "r") as f:
         contents = f.read()


Test patch: