def test_jobs_registration(self): """ Check that plugin jobs are registered correctly and discoverable. """ from dummy_plugin.jobs import DummyJob self.assertIn(DummyJob, registry.get("plugin_jobs", [])) self.assertEqual( DummyJob, get_job("plugins/dummy_plugin.jobs/DummyJob"), ) self.assertIn( "plugins/dummy_plugin.jobs/DummyJob", get_job_classpaths(), ) jobs_dict = get_jobs() self.assertIn("plugins", jobs_dict) self.assertIn("dummy_plugin.jobs", jobs_dict["plugins"]) self.assertEqual( "DummyPlugin jobs", jobs_dict["plugins"]["dummy_plugin.jobs"].get("name"), ) self.assertIn("jobs", jobs_dict["plugins"]["dummy_plugin.jobs"]) self.assertIn( "DummyJob", jobs_dict["plugins"]["dummy_plugin.jobs"]["jobs"], ) self.assertEqual( DummyJob, jobs_dict["plugins"]["dummy_plugin.jobs"]["jobs"]["DummyJob"], )
def test_git_datasource_contents_registration(self): """ Check that plugin DatasourceContents are registered. """ registered_datasources = registry.get("datasource_contents", {}).get("extras.gitrepository", []) plugin_datasource = DatasourceContent( name="text files", content_identifier="dummy_plugin.textfile", icon="mdi-note-text", weight=1000, callback=refresh_git_text_files, ) for datasource in registered_datasources: if datasource.name == plugin_datasource.name: self.assertEqual(datasource.content_identifier, plugin_datasource.content_identifier) self.assertEqual(datasource.icon, plugin_datasource.icon) self.assertEqual(datasource.weight, plugin_datasource.weight) self.assertEqual(datasource.callback, plugin_datasource.callback) break else: self.fail( f"Datasource {plugin_datasource.name} not found in registered_datasources!" )
def test_jobs_registration(self): """ Check that plugin jobs are registered correctly and discoverable. """ from example_plugin.jobs import ExampleJob self.assertIn(ExampleJob, registry.get("plugin_jobs", [])) self.assertEqual( ExampleJob, get_job("plugins/example_plugin.jobs/ExampleJob"), ) self.assertIn( "plugins/example_plugin.jobs/ExampleJob", get_job_classpaths(), ) jobs_dict = get_jobs() self.assertIn("plugins", jobs_dict) self.assertIn("example_plugin.jobs", jobs_dict["plugins"]) self.assertEqual( "ExamplePlugin jobs", jobs_dict["plugins"]["example_plugin.jobs"].get("name"), ) self.assertIn("jobs", jobs_dict["plugins"]["example_plugin.jobs"]) self.assertIn( "ExampleJob", jobs_dict["plugins"]["example_plugin.jobs"]["jobs"], ) self.assertEqual( ExampleJob, jobs_dict["plugins"]["example_plugin.jobs"]["jobs"]["ExampleJob"], )
def test_extras_features_graphql(self): """ Check that plugin GraphQL Types are registered. """ registered_models = registry.get("model_features", {}).get("graphql", {}) self.assertIn("dummy_plugin", registered_models.keys()) self.assertIn("dummymodel", registered_models["dummy_plugin"])
def test_git_datasource_contents(self): """ Check that plugin DatasourceContents are registered. """ registered_datasources = registry.get("datasource_contents", {}).get("extras.gitrepository", []) self.assertIn( DatasourceContent( name="text files", content_identifier="dummy_plugin.textfile", icon="mdi-note-text", callback=refresh_git_text_files, ), registered_datasources, )
def generate_query_mixin(): """Generates and returns a class definition representing a GraphQL schema.""" logger.info("Beginning generation of Nautobot GraphQL schema") class_attrs = {} def already_present(model): """Check if a model and its resolvers are staged to added to the Mixin.""" single_item_name = str_to_var_name(model._meta.verbose_name) list_name = str_to_var_name(model._meta.verbose_name_plural) if single_item_name in class_attrs: logger.warning( f"Unable to register the schema single type '{single_item_name}' in GraphQL, " f"there is already another type {class_attrs[single_item_name]._type} registered under this name" ) return True if list_name in class_attrs: logger.warning( f"Unable to register the schema list type '{list_name}' in GraphQL, " f"there is already another type {class_attrs[list_name]._type} registered under this name" ) return True return False logger.debug( "Generating dynamic schemas for all models in the models_features graphql registry" ) # - Ensure an attribute/schematype with the same name doesn't already exist registered_models = registry.get("model_features", {}).get("graphql", {}) for app_name, models in registered_models.items(): for model_name in models: try: # Find the model class based on the content type ct = ContentType.objects.get(app_label=app_name, model=model_name) model = ct.model_class() except ContentType.DoesNotExist: logger.warning( f"Unable to generate a schema type for the model '{app_name}.{model_name}' in GraphQL," "this model doesn't have an associated ContentType, please create the Object manually." ) continue type_identifier = f"{app_name}.{model_name}" if type_identifier in registry["graphql_types"].keys(): # Skip models that have been added statically continue schema_type = generate_schema_type(app_name=app_name, model=model) registry["graphql_types"][type_identifier] = schema_type logger.debug("Adding plugins' statically defined graphql schema types") # After checking for conflict for schema_type in registry["plugin_graphql_types"]: model = schema_type._meta.model type_identifier = f"{model._meta.app_label}.{model._meta.model_name}" if type_identifier in registry["graphql_types"]: logger.warning( f'Unable to load schema type for the model "{type_identifier}" as there is already another type ' "registered under this name. If you are seeing this message during plugin development, check to " "make sure that you aren't using @extras_features(\"graphql\") on the same model you're also " "defining a custom GraphQL type for.") else: registry["graphql_types"][type_identifier] = schema_type logger.debug( "Extending all registered schema types with dynamic attributes") for schema_type in registry["graphql_types"].values(): if already_present(schema_type._meta.model): continue schema_type = extend_schema_type(schema_type) class_attrs.update(generate_attrs_for_schema_type(schema_type)) QueryMixin = type("QueryMixin", (object, ), class_attrs) logger.info("Generation of Nautobot GraphQL schema complete") return QueryMixin
def generate_query_mixin(): """Generates and returns a class definition representing a GraphQL schema.""" class_attrs = {} def already_present(model): """Check if a model and its resolvers are staged to added to the Mixin.""" single_item_name = str_to_var_name(model._meta.verbose_name) list_name = str_to_var_name(model._meta.verbose_name_plural) if single_item_name in class_attrs: logger.warning( f"Unable to register the schema type '{single_item_name}' in GraphQL from '{app_name}':'{model_name}'," "there is already another type registered under this name") return True if list_name in class_attrs: logger.warning( f"Unable to register the schema type '{list_name}' in GraphQL from '{app_name}':'{model_name}'," "there is already another type registered under this name") return True # Generate SchemaType Dynamically for all Models registered in the model_features registry # - Ensure an attribute/schematype with the same name doesn't already exist registered_models = registry.get("model_features", {}).get("graphql", {}) for app_name, models in registered_models.items(): for model_name in models: try: # Find the model class based on the content type ct = ContentType.objects.get(app_label=app_name, model=model_name) model = ct.model_class() except ContentType.DoesNotExist: logger.warning( f"Unable to generate a schema type for the model '{app_name}.{model_name}' in GraphQL," "this model doesn't have an associated ContentType, please create the Object manually." ) continue type_identifier = f"{app_name}.{model_name}" if type_identifier in registry["graphql_types"].keys(): # Skip models that have been added statically continue schema_type = generate_schema_type(app_name=app_name, model=model) registry["graphql_types"][type_identifier] = schema_type # Add all objects in the plugin registry to the main registry # After checking for conflict for schema_type in registry["plugin_graphql_types"]: model = schema_type._meta.model type_identifier = f"{model._meta.app_label}.{model._meta.model_name}" if type_identifier not in registry["graphql_types"].keys(): registry["graphql_types"][type_identifier] = schema_type # Extend schema_type with dynamic attributes for all object defined in the registry for schema_type in registry["graphql_types"].values(): if already_present(schema_type._meta.model): continue schema_type = extend_schema_type(schema_type) class_attrs.update(generate_attrs_for_schema_type(schema_type)) QueryMixin = type("QueryMixin", (object, ), class_attrs) return QueryMixin