class SynchronizeOptions(AttributesContainer): """Synchronization option.""" upload_private_comments: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload private comments', description='Upload the report private comments into the bug trackers', default=False, ) upload_public_comments: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload public comments', description='Upload the report public comments into the bug trackers', default=False, ) upload_details_updates: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload details updates', description='Upload the report details updates into the bug trackers', default=False, ) upload_rewards: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload rewards', description='Upload the report rewards into the bug trackers', default=False, ) upload_status_updates: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload status updates', description='Upload the report status updates into the bug trackers', default=False, ) def __init__( self, upload_private_comments: Optional[bool] = None, upload_public_comments: Optional[bool] = None, upload_details_updates: Optional[bool] = None, upload_rewards: Optional[bool] = None, upload_status_updates: Optional[bool] = None, **kwargs: Any, ): """ Initialize self. Args: upload_private_comments: a flag indicating whether to upload private comments to the bugtrackers upload_public_comments: a flag indicating whether to upload public comments to the bugtrackers upload_details_updates: a flag indicating whether to upload details updates to the bugtrackers upload_rewards: a flag indicating whether to upload rewards to the bugtrackers upload_status_updates: a flag indicating whether to upload status updates to the bugtrackers kwargs: keyword arguments """ super().__init__(**kwargs) self.upload_private_comments = upload_private_comments self.upload_public_comments = upload_public_comments self.upload_details_updates = upload_details_updates self.upload_rewards = upload_rewards self.upload_status_updates = upload_status_updates
def _get_pattern_properties( root_schema: Json, attribute: Attribute[Any], ) -> Json: value_type = attribute.value_type instance = value_type() item_values_type = instance.values_type if isinstance(item_values_type, SubtypableMetaclass): any_of = [] for type_name, type_class in item_values_type.get_registered_subtypes( ).items(): any_of.append( _attribute_to_schema( root_schema=root_schema, attribute=Attribute.create(value_type=type_class, ), extra_properties={ 'type': { 'const': type_name, }, }, ), ) return { 'anyOf': any_of, } return _attribute_to_schema( root_schema=root_schema, attribute=Attribute.create(value_type=item_values_type, ), )
class FeedbackOptions(AttributesContainer): """Feedback option.""" download_tracker_comments: BoolAttributeType = Attribute.create( value_type=bool, short_description='Download bug trackers comments', description='Download comments from the bug tracker and put them into the report', default=False, ) issue_closed_to_report_afv: BoolAttributeType = Attribute.create( value_type=bool, short_description='Issue closed to report AFV', description='Set the report status to "Ask for Fix Verification" when the tracker issue is closed', default=False, ) def __init__( self, download_tracker_comments: Optional[bool] = None, issue_closed_to_report_afv: Optional[bool] = None, **kwargs: Any, ): """ Initialize self. Args: download_tracker_comments: a flag indicating whether to download comments from the bug tracker and put them into the report issue_closed_to_report_afv: a flag indicating whether to set report status to "Ask for Fix Verification" when tracker issue is closed kwargs: keyword arguments """ super().__init__(**kwargs) self.download_tracker_comments = download_tracker_comments self.issue_closed_to_report_afv = issue_closed_to_report_afv
class Program(AttributesContainer): """A program and its associated bugtrackers.""" slug: StrAttributeType = Attribute.create( value_type=str, short_description='Program slug', description='Program slug', required=True, validator=not_blank_validator, ) synchronize_options: SynchronizeOptionsAttributeType = Attribute.create( value_type=SynchronizeOptions, short_description='Synchronization options', required=True, ) feedback_options: FeedbackOptionsAttributeType = Attribute.create( value_type=FeedbackOptions, short_description='Feedback options', required=True, ) bugtrackers_name: BugtrackersNameAttributeType = Attribute.create( value_type=Bugtrackers, short_description='Bug trackers', description='Bug trackers names', required=True, validator=length_one_validator, ) def __init__( self, slug: Optional[str] = None, synchronize_options: SynchronizeOptionsInitType = None, feedback_options: FeedbackOptionsInitType = None, bugtrackers_name: BugtrackersNameInitType = None, **kwargs: Any, ): """ Initialize the program. Args: slug: a program slug synchronize_options: synchronization options feedback_options: feedback options bugtrackers_name: a list of bugtrackers kwargs: keyword arguments """ super().__init__(**kwargs) self.slug = slug if not synchronize_options: synchronize_options = SynchronizeOptions() self.synchronize_options = synchronize_options if not feedback_options: feedback_options = FeedbackOptions() self.feedback_options = feedback_options if bugtrackers_name: if isinstance(bugtrackers_name, List): self.bugtrackers_name = Bugtrackers(bugtrackers_name) else: self.bugtrackers_name = cast(Bugtrackers, bugtrackers_name)
class OAuthSettings(AttributesContainer): """OAuth settings.""" client_id: StrAttributeType = Attribute.create( value_type=str, short_description='Client ID', description='OAuthSettings client ID', required=True, validator=not_blank_validator, ) client_secret: StrAttributeType = Attribute.create( value_type=str, short_description='Secret', description='OAuthSettings client secret', required=True, secret=True, validator=not_blank_validator, ) redirect_uri: StrAttributeType = Attribute.create( value_type=str, short_description='Redirect URI', description='OAuthSettings redirect URI', required=True, validator=url_validator, ) def __init__( self, client_id: Optional[str] = None, client_secret: Optional[str] = None, redirect_uri: Optional[str] = None, **kwargs: Any, ) -> None: """ Initialize the settings. Args: client_id: an OAuth v2 client ID client_secret: an OAuth v2 client secret redirect_uri: a redirect URI kwargs: keyword arguments """ super().__init__(**kwargs) self.client_id = client_id self.client_secret = client_secret self.redirect_uri = redirect_uri def validate(self, ) -> None: """Validate the object.""" attributes = ( self.client_id, self.client_secret, self.redirect_uri, ) if not any(attributes): return super().validate()
class Container(AttributesContainer): # noqa: WPS431 not_sec = Attribute.create( value_type=str, secret=False, ) sec = Attribute.create( value_type=str, secret=True, )
class YesWeHackConfiguration(AttributesContainer): """A configuration for YesWeHack.""" api_url: StrAttributeType = Attribute.create( value_type=str, short_description='API URL', description='Base URL of the YWH API', default='https://api.yeswehack.com', validator=url_validator, ) pat: StrAttributeType = Attribute.create( value_type=str, short_description='Personal Access Token', description='Personal Access Token', required=True, secret=True, validator=not_blank_validator, ) verify: BoolAttributeType = Attribute.create( value_type=bool, short_description='Verify TLS', description="Verify server's TLS certificate", default=True, ) programs: ProgramsAttributeType = Attribute.create( value_type=Programs, short_description='Programs', description='Programs', required=True, validator=not_empty_validator, ) def __init__( self, api_url: Optional[str] = None, pat: Optional[str] = None, verify: Optional[bool] = None, programs: ProgramsInitType = None, **kwargs: Any, ): """ Initialize the configuration. Args: api_url: a YesWeHack API URL pat: a Personal Access Token verify: a flag indicating whether to check SSL/TLS connection programs: a list of Programs kwargs: keyword arguments """ super().__init__(**kwargs) self.api_url = api_url self.pat = pat self.verify = verify self.programs = programs
def test_attribute_validate_required_no_default(self) -> None: attr = Attribute.create( value_type=str, required=True, ) with self.assertRaises(BaseAttributeError): attr.validate(value=None)
class CTracker(TrackerConfiguration): # noqa: WPS431 description = Attribute.create(value_type=str, ) def __init__( self, description: Optional[str], ): super().__init__() self.description = description
class ATracker(TrackerConfiguration): # noqa: WPS431 name = Attribute.create(value_type=str, ) def __init__( self, name: Optional[str], ): super().__init__() self.name = name
def test_attribute_validator_fail(self) -> None: def validator(value: str) -> None: # noqa: WPS430 raise ValidatorError() attr = Attribute.create( value_type=str, validator=validator, ) with self.assertRaises(BaseAttributeError): attr.validate(value='123')
def _root_configuration_to_schema() -> Json: schema = { '$schema': 'http://json-schema.org/draft-07/schema', 'title': 'Root configuration', 'description': 'Root configuration for ywh2bt synchronization', 'definitions': {}, } schema.update( _attributes_container_to_schema( root_schema=schema, attribute=Attribute.create(value_type=RootConfiguration, ), as_ref=False, ), ) return schema
def _attribute_container_list_to_schema( root_schema: Json, attribute: Attribute[AttributesContainerList[Any]], extra_properties: Optional[Json] = None, as_ref: bool = False, ) -> Json: value_type = attribute.value_type instance = value_type() # type: ignore item_values_type = instance.values_type return { 'type': 'array', 'items': _attribute_to_schema( root_schema=root_schema, attribute=Attribute.create(value_type=item_values_type, ), ), }
class Container(AttributesContainer): # noqa: WPS431 str_field = Attribute.create(value_type=str, ) int_field = Attribute.create(value_type=int, ) bool_field = Attribute.create(value_type=bool, ) sub_field = Attribute.create(value_type=ChildAttributesContainer, )
class ChildAttributesContainer(AttributesContainer): # noqa: WPS431 field = Attribute.create(value_type=str, )
def test_attribute_validate_wrong_type(self) -> None: attr = Attribute.create(value_type=str, ) with self.assertRaises(BaseAttributeError): attr.validate(value=123)
def test_attribute_as_repr_secret(self) -> None: attr = Attribute.create( value_type=str, secret=True, ) self.assertEqual("<secret-str '***'>", attr.as_repr('my value'))
def test_str_attribute_as_repr(self) -> None: attr = Attribute.create(value_type=str, ) self.assertEqual("'my value'", attr.as_repr('my value'))
class Container(AttributesContainer): # noqa: WPS431 field = Attribute.create( value_type=str, default='default-value', )
class GitHubConfiguration(TrackerConfiguration): """A class describing the configuration of a GitHub tracker.""" url: StrAttributeType = Attribute.create( value_type=str, short_description='API URL', description='Base URL of the GitHub API', default='https://api.github.com', validator=url_validator, ) token: StrAttributeType = Attribute.create( value_type=str, short_description='API token', description='User private token for the GitHub API', required=True, secret=True, validator=not_blank_validator, ) project: StrAttributeType = Attribute.create( value_type=str, short_description='Project path', description='Path to the project on GitHub', required=True, validator=not_blank_validator, ) verify: BoolAttributeType = Attribute.create( value_type=bool, short_description='Verify TLS', description="Verify server's TLS certificate", default=True, ) github_cdn_on: BoolAttributeType = Attribute.create( value_type=bool, short_description='Use CDN', description='Enable or disable saving attachment file to GitHub CDN', default=False, ) login: StrAttributeType = Attribute.create( value_type=str, short_description='Login', description= 'User login for the GitHub server. Required only if github_cdn_on is true', secret=False, ) password: StrAttributeType = Attribute.create( value_type=str, short_description='Password', description= 'User password for the GitHub server. Required only if github_cdn_on is true', secret=True, ) def __init__( self, url: Optional[Text] = None, token: Optional[Text] = None, project: Optional[Text] = None, verify: Optional[bool] = None, github_cdn_on: Optional[bool] = None, login: Optional[Text] = None, password: Optional[Text] = None, **kwargs: Any, ): """ Initialize the configuration. Args: url: a GitHub API URL token: a GitHub API token project: a GitHub project name verify: a flag indicating whether to check SSL/TLS connection github_cdn_on: a flag indicating whether to save attachment file to GitHub CDN login: a GitLab user login ; used when github_cdn_on is true password: a GitLab user password ; used when github_cdn_on is true kwargs: keyword arguments """ super().__init__(**kwargs) self.url = url self.token = token self.project = project self.verify = verify self.github_cdn_on = github_cdn_on self.login = login self.password = password def validate(self) -> None: """ Validate the container. # noqa: DAR401, DAR402 Raises: AttributesError: if the container is not valid """ super_error: Optional[AttributesError] = None try: super().validate() except AttributesError as e: super_error = e errors = {} if self.github_cdn_on: errors.update(self._ensure_login_password(), ) if errors: if not super_error: super_error = AttributesError( message='Validation error', errors={}, context=self, ) super_error.errors.update(errors) if super_error: raise super_error def _ensure_login_password(self, ) -> Dict[str, MissingAttributeError]: errors = {} if self.login is None: errors['login'] = MissingAttributeError( message= "Expecting value for attribute 'login' when 'github_on_cdn' is True", context=self, ) if self.password is None: errors['password'] = MissingAttributeError( message= "Expecting value for attribute 'password' when 'github_on_cdn' is True", context=self, ) return errors
class MyUnregisteredTracker(TrackerConfiguration): # noqa: WPS431 prop = Attribute.create( value_type=str, required=True, )
class ChildContainer(AttributesContainer): field = Attribute.create(value_type=str, )
class GitLabConfiguration(TrackerConfiguration): """A class describing the configuration of a GitLab tracker.""" url: StrAttributeType = Attribute.create( value_type=str, short_description='API URL', description='Base URL of the GitLab server', default='https://gitlab.com', validator=url_validator, ) token: StrAttributeType = Attribute.create( value_type=str, short_description='API token', description='User private token for the GitLab API', required=True, secret=True, validator=not_blank_validator, ) project: StrAttributeType = Attribute.create( value_type=str, short_description='Project path', description='Path to the project on GitLab', required=True, validator=not_blank_validator, ) verify: BoolAttributeType = Attribute.create( value_type=bool, short_description='Verify TLS', description="Verify server's TLS certificate", default=True, ) confidential: BoolAttributeType = Attribute.create( value_type=bool, short_description='Confidential issues', description='Mark created issues as confidential', default=False, ) def __init__( self, url: Optional[Text] = None, token: Optional[Text] = None, project: Optional[Text] = None, verify: Optional[bool] = None, confidential: Optional[bool] = None, **kwargs: Any, ): """ Initialize the configuration. Args: url: a GitLab API URL token: a GitLab API token project: a GitLab project name verify: a flag indicating whether to check SSL/TLS connection confidential: a flag indicating whether to mark created issues as confidential kwargs: keyword arguments """ super().__init__(**kwargs) self.url = url self.token = token self.project = project self.verify = verify self.confidential = confidential
class ServiceNowConfiguration(TrackerConfiguration): """A class describing the configuration of a ServiceNow tracker.""" host: StrAttributeType = Attribute.create( value_type=str, short_description='Instance host', description='Host of the ServiceNow instance', required=True, validator=host_validator, ) login: StrAttributeType = Attribute.create( value_type=str, short_description='Login', description='User login for the ServiceNow instance', required=True, secret=False, validator=not_blank_validator, ) password: StrAttributeType = Attribute.create( value_type=str, short_description='Password', description='User password for the ServiceNow instance', required=True, secret=True, validator=not_blank_validator, ) use_ssl: BoolAttributeType = Attribute.create( value_type=bool, short_description='Use SSL', description='Use SSL connection', default=True, ) verify: BoolAttributeType = Attribute.create( value_type=bool, short_description='Verify SSL', description='Verify SSL certs', default=True, ) def __init__( self, host: Optional[Text] = None, login: Optional[Text] = None, password: Optional[Text] = None, use_ssl: Optional[bool] = None, verify: Optional[bool] = None, **kwargs: Any, ): """ Initialize the configuration. Args: host: a ServiceNow instance host login: a ServiceNow user login password: a ServiceNow user password use_ssl: a flag indicating whether to use SSL/TLS connection verify: a flag indicating whether to check SSL/TLS connection kwargs: keyword arguments """ super().__init__(**kwargs) self.host = host self.login = login self.password = password self.use_ssl = use_ssl self.verify = verify
def test_int_attribute_as_repr(self) -> None: attr = Attribute.create(value_type=int, ) self.assertEqual('123', attr.as_repr(123))
class SynchronizeOptions(AttributesContainer): """Synchronization option.""" upload_private_comments: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload private comments', description='Upload the report private comments into the bug tracker', default=False, ) upload_public_comments: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload public comments', description='Upload the report public comments into the bug tracker', default=False, ) upload_cvss_updates: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload CVSS updates', description='Upload the report CVSS updates into the bug tracker', default=False, ) upload_details_updates: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload details updates', description='Upload the report details updates into the bug tracker', default=False, ) upload_priority_updates: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload priority updates', description='Upload the report priority updates into the bug tracker', default=False, ) upload_rewards: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload rewards', description='Upload the report rewards into the bug tracker', default=False, ) upload_status_updates: BoolAttributeType = Attribute.create( value_type=bool, short_description='Upload status updates', description='Upload the report status updates into the bug tracker', default=False, ) recreate_missing_issues: BoolAttributeType = Attribute.create( value_type=bool, short_description='Recreate missing issues', description=( 'Recreate issues that were created by a previous synchronization ' + 'but are not found into the bug tracker anymore' ), default=True, ) def __init__( self, upload_private_comments: Optional[bool] = None, upload_public_comments: Optional[bool] = None, upload_details_updates: Optional[bool] = None, upload_cvss_updates: Optional[bool] = None, upload_priority_updates: Optional[bool] = None, upload_rewards: Optional[bool] = None, upload_status_updates: Optional[bool] = None, recreate_missing_issues: Optional[bool] = None, **kwargs: Any, ): """ Initialize self. Args: upload_private_comments: a flag indicating whether to upload private comments to the bug tracker upload_public_comments: a flag indicating whether to upload public comments to the bug tracker upload_cvss_updates: a flag indicating whether to upload CVSS updates to the bug tracker upload_details_updates: a flag indicating whether to upload details updates to the bug tracker upload_priority_updates: a flag indicating whether to upload priority updates into the bug tracker upload_rewards: a flag indicating whether to upload rewards to the bug tracker upload_status_updates: a flag indicating whether to upload status updates to the bug tracker recreate_missing_issues: a flag indicating whether to recreate missing issues kwargs: keyword arguments """ super().__init__(**kwargs) self.upload_private_comments = upload_private_comments self.upload_public_comments = upload_public_comments self.upload_cvss_updates = upload_cvss_updates self.upload_details_updates = upload_details_updates self.upload_priority_updates = upload_priority_updates self.upload_rewards = upload_rewards self.upload_status_updates = upload_status_updates self.recreate_missing_issues = recreate_missing_issues
class YesWeHackConfiguration(AttributesContainer): """A configuration for YesWeHack.""" api_url: StrAttributeType = Attribute.create( value_type=str, short_description='API URL', description='Base URL of the YWH API', default='https://apps.yeswehack.com', validator=url_validator, ) apps_headers: AppHeadersAttributeType = Attribute.create( short_description='Apps headers', value_type=Headers, required=True, validator=dict_has_non_blank_key_validator('X-YesWeHack-Apps', ), ) login: StrAttributeType = Attribute.create( value_type=str, short_description='Login', description='User login', required=True, validator=not_blank_validator, ) password: StrAttributeType = Attribute.create( value_type=str, short_description='Password', description='User password', required=True, secret=True, validator=not_blank_validator, ) oauth_args: OAuthArgsAttributeType = Attribute.create( value_type=OAuthSettings, short_description='OAuth settings', description='OAuth settings', ) verify: BoolAttributeType = Attribute.create( value_type=bool, short_description='Verify TLS', description="Verify server's TLS certificate", default=True, ) totp: BoolAttributeType = Attribute.create( value_type=bool, short_description='Use TOTP', description=''.join(( 'Use TOTP\n', "Apps API doesn't require TOTP authentication, even if corresponding user has TOTP enabled.\n", 'However, on a secured program, information is limited for user with TOTP disabled, even in apps.\n', 'As a consequence, to allow proper bug tracking integration on a secured program,', 'program consumer must have TOTP enabled and, in BTI configuration TOTP must be set to false', )), default=True, deprecated=True, ) programs: ProgramsAttributeType = Attribute.create( value_type=Programs, short_description='Programs', description='Programs', required=True, validator=not_empty_validator, ) def __init__( self, api_url: Optional[str] = None, apps_headers: AppHeadersInitType = None, login: Optional[str] = None, password: Optional[str] = None, oauth_args: OAuthArgsInitType = None, verify: Optional[bool] = None, totp: Optional[bool] = None, programs: ProgramsInitType = None, **kwargs: Any, ): """ Initialize the configuration. Args: api_url: a YesWeHack API URL apps_headers: a list of HTTP headers to be added to API calls login: a YesWeHack user login password: a YesWeHack user password oauth_args: settings for API OAuth authentication verify: a flag indicating whether to check SSL/TLS connection totp: a flag indicating whether to use TOTP programs: a list of Programs kwargs: keyword arguments """ super().__init__(**kwargs) self.api_url = api_url self.apps_headers = apps_headers self.login = login self.password = password self.oauth_args = oauth_args self.verify = verify self.totp = totp self.programs = programs
class RootConfiguration(AttributesContainer): """A root configuration.""" bugtrackers: BugtrackersAttributeType = Attribute.create( value_type=Trackers, short_description='Trackers', description='Trackers to be synchronized with YesWeHack', required=True, validator=not_empty_validator, ) yeswehack: YesWeHackAttributeType = Attribute.create( value_type=YesWeHackConfigurations, short_description='YesWeHack', required=True, validator=not_empty_validator, ) def __init__( self, bugtrackers: BugtrackersInitType = None, yeswehack: YesWeHackInitType = None, **kwargs: Any, ): """ Initialize the configuration. Args: bugtrackers: a configuration for the bugtrackers yeswehack: a configuration for YesWeHack kwargs: keyword arguments """ super().__init__(**kwargs) self.bugtrackers = bugtrackers self.yeswehack = yeswehack def validate(self) -> None: """ Validate the configuration. Raises: AttributesError: if the configuration is invalid # noqa: DAR401 # noqa: DAR402 """ super_error: Optional[AttributesError] = None try: super().validate() except AttributesError as e: super_error = e errors = {} if self.yeswehack: errors.update( self._ensure_declared_trackers( trackers=cast(Trackers, self.bugtrackers or {}), yeswehack=cast(YesWeHackConfigurations, self.yeswehack or {}), ), ) if errors: if not super_error: super_error = AttributesError( message='Validation error', errors={}, context=self, ) super_error.errors.update(errors) if super_error: raise super_error def _ensure_declared_trackers( self, trackers: Trackers, yeswehack: YesWeHackConfigurations, ) -> Dict[str, AttributesError]: errors = {} for yeswehack_name, yeswehack_config in yeswehack.items(): config_errors = self._ensure_bugtrackers_name( trackers=trackers, programs=cast(Programs, yeswehack_config.programs or {}), ) for key, error in config_errors.items(): errors[f'yeswehack.{yeswehack_name}.{key}'] = error return errors def _ensure_bugtrackers_name( self, trackers: Trackers, programs: Programs, ) -> Dict[str, AttributesError]: errors = {} for i, program in enumerate(programs): if not program.bugtrackers_name: continue for j, bugtracker_name in enumerate(program.bugtrackers_name): if bugtracker_name not in trackers: errors[f'programs[{i}].bugtrackers_name[{j}]'] = AttributesError( message= f'Bugtracker not {repr(bugtracker_name)} declared in bugtrackers', errors={}, context=self, ) return errors
class Container(AttributesContainer): # noqa: WPS431 field = Attribute.create( value_type=str, required=True, )
class JiraConfiguration(TrackerConfiguration): """A class describing the configuration of a Jira tracker.""" url: StrAttributeType = Attribute.create( value_type=str, short_description='API URL', description='Base URL of the Jira server', required=True, validator=url_validator, ) login: StrAttributeType = Attribute.create( value_type=str, short_description='Login', description='User login for the Jira server', required=True, secret=False, validator=not_blank_validator, ) password: StrAttributeType = Attribute.create( value_type=str, short_description='Password', description='User password or API token for the Jira server', required=True, secret=True, validator=not_blank_validator, ) project: StrAttributeType = Attribute.create( value_type=str, short_description='Project slug', description='Jira slug', required=True, validator=not_blank_validator, ) verify: BoolAttributeType = Attribute.create( value_type=bool, short_description='Verify SSL', description='Verify SSL certs', default=True, ) issuetype: StrAttributeType = Attribute.create( value_type=str, short_description='Issue type', description='Issue type (sensitive to account language)', default='Task', ) issue_closed_status: StrAttributeType = Attribute.create( value_type=str, short_description='Issue closed status', description='Issue closed status (sensitive to account language)', default='Closed', ) def __init__( self, url: Optional[Text] = None, login: Optional[Text] = None, password: Optional[Text] = None, project: Optional[Text] = None, verify: Optional[bool] = None, issuetype: Optional[Text] = None, issue_closed_status: Optional[Text] = None, **kwargs: Any, ): """ Initialize the configuration. Args: url: a Jira API URL login: a Jira API user login password: a Jira API user password project: a Jira project name verify: a flag indicating whether to check SSL/TLS connection issuetype: a Jira issue type issue_closed_status: a Jira name when the issue is closed kwargs: keyword arguments """ super().__init__(**kwargs) self.url = url self.login = login self.password = password self.project = project self.verify = verify self.issuetype = issuetype self.issue_closed_status = issue_closed_status