nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: ariga/atlas
Pull request #1325 (2022-12-03 08:56:46)

schemahcl: validate variable type definition


Patch:
diff --git a/schemahcl/context.go b/schemahcl/context.go
index 663cec15..42fe187a 100644
--- a/schemahcl/context.go
+++ b/schemahcl/context.go
@@ -44,6 +44,11 @@ func (s *State) setInputVals(ctx *hcl.EvalContext, body hcl.Body, input map[stri
 	for _, v := range doc.Vars {
 		var vv cty.Value
 		switch iv, ok := input[v.Name]; {
+		case !v.Type.Type().IsCapsuleType():
+			return fmt.Errorf(
+				"invalid type %q for variable %q. Valid types are: string, number, bool, list, map, or set",
+				v.Type.AsString(), v.Name,
+			)
 		case ok:
 			vv = iv
 		case v.Default != cty.NilVal:


Test patch:
diff --git a/schemahcl/context_test.go b/schemahcl/context_test.go
index decf66f7..7b84208b 100644
--- a/schemahcl/context_test.go
+++ b/schemahcl/context_test.go
@@ -502,6 +502,7 @@ variable "convert_bool" {
 variable "strings" {
   type = list(string)
   default = ["a", "b"]
+  description = "description is a valid attribute"
 }
 
 name = var.name
@@ -512,7 +513,6 @@ convert_int = var.convert_int
 convert_bool = var.convert_bool
 strings = var.strings
 `
-	state := New()
 	var test struct {
 		Name        string   `spec:"name"`
 		Default     string   `spec:"default"`
@@ -522,7 +522,7 @@ strings = var.strings
 		ConvertBool bool     `spec:"convert_bool"`
 		Strings     []string `spec:"strings"`
 	}
-	err := state.EvalBytes([]byte(h), &test, map[string]cty.Value{
+	err := New().EvalBytes([]byte(h), &test, map[string]cty.Value{
 		"name":         cty.StringVal("rotemtam"),
 		"int":          cty.NumberIntVal(42),
 		"bool":         cty.BoolVal(true),
@@ -539,3 +539,21 @@ strings = var.strings
 	require.EqualValues(t, true, test.ConvertBool)
 	require.EqualValues(t, []string{"a", "b"}, test.Strings)
 }
+
+func TestVariable_InvalidType(t *testing.T) {
+	h := `
+variable "name" {
+  type = "int"
+  default = "boring"
+}`
+	err := New().EvalBytes([]byte(h), &struct{}{}, nil)
+	require.EqualError(t, err, `invalid type "int" for variable "name". Valid types are: string, number, bool, list, map, or set`)
+
+	h = `
+variable "name" {
+  type = "boring"
+  default = "boring"
+}`
+	err = New().EvalBytes([]byte(h), &struct{}{}, nil)
+	require.EqualError(t, err, `invalid type "boring" for variable "name". Valid types are: string, number, bool, list, map, or set`)
+}
Repository: ariga/atlas
Pull request #1350 (2022-12-14 13:10:46)

sql/mysql/mysqlversion: ignore server build info on compare
Fixed https://github.com/ariga/atlas/issues/1349


Patch:
diff --git a/sql/mysql/internal/mysqlversion/mysqlversion.go b/sql/mysql/internal/mysqlversion/mysqlversion.go
index dd784a9e..ba23b7be 100644
--- a/sql/mysql/internal/mysqlversion/mysqlversion.go
+++ b/sql/mysql/internal/mysqlversion/mysqlversion.go
@@ -116,11 +116,14 @@ func (v V) TiDB() bool {
 // semantic version precedence.
 func (v V) Compare(w string) int {
 	u := string(v)
-	switch {
+	switch idx := strings.Index(u, "-"); {
 	case v.Maria():
 		u = u[:strings.Index(u, "MariaDB")-1]
 	case v.TiDB():
 		u = u[:strings.Index(u, "TiDB")-1]
+	case idx > 0:
+		// Remove server build information, if any.
+		u = u[:idx]
 	}
 	return semver.Compare("v"+u, "v"+w)
 }


Test patch:
diff --git a/sql/mysql/internal/mysqlversion/mysqlversion_test.go b/sql/mysql/internal/mysqlversion/mysqlversion_test.go
new file mode 100644
index 00000000..2001bd69
--- /dev/null
+++ b/sql/mysql/internal/mysqlversion/mysqlversion_test.go
@@ -0,0 +1,34 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
+package mysqlversion_test
+
+import (
+	"testing"
+
+	"ariga.io/atlas/sql/mysql/internal/mysqlversion"
+)
+
+func TestV_SupportsGeneratedColumns(t *testing.T) {
+	tests := []struct {
+		v    string
+		want bool
+	}{
+		{"5.6", false},
+		{"5.7", true},
+		{"5.7.0", true},
+		{"5.7.40-0ubuntu0.18.04.1", true},
+		{"8.0.0", true},
+		{"10.1.1-MariaDB", false},
+		{"10.2.1-MariaDB-10.2.1+maria~bionic", true},
+		{"10.3.1-MariaDB-10.2.1+maria~bionic-log", true},
+	}
+	for _, tt := range tests {
+		t.Run(tt.v, func(t *testing.T) {
+			if got := mysqlversion.V(tt.v).SupportsGeneratedColumns(); got != tt.want {
+				t.Errorf("V.SupportsGeneratedColumns() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
Repository: ariga/atlas
Pull request #1392 (2023-01-08 08:50:24)

sql/sqlclient: improve url/opener error
Replaced this error: `Error: sql/sqlclient: no opener was registered with name ""` with a helpful one. 


Patch:
diff --git a/doc/website/docusaurus.config.js b/doc/website/docusaurus.config.js
index 56a05104..fdea14e9 100644
--- a/doc/website/docusaurus.config.js
+++ b/doc/website/docusaurus.config.js
@@ -194,6 +194,10 @@ module.exports = {
             to: '/guides/ddl',
             from: '/knowledge/ddl',
           },
+          {
+            to: '/concepts/url',
+            from: '/url',
+          },
         ],
       },
     ],
diff --git a/sql/sqlclient/client.go b/sql/sqlclient/client.go
index 35cc0dda..8f677ceb 100644
--- a/sql/sqlclient/client.go
+++ b/sql/sqlclient/client.go
@@ -199,9 +199,12 @@ func OpenURL(ctx context.Context, u *url.URL, opts ...OpenOption) (*Client, erro
 			return nil, err
 		}
 	}
+	if u.Scheme == "" {
+		return nil, errors.New("sql/sqlclient: missing driver. See: https://atlasgo.io/url")
+	}
 	v, ok := drivers.Load(u.Scheme)
 	if !ok {
-		return nil, fmt.Errorf("sql/sqlclient: no opener was registered with name %q", u.Scheme)
+		return nil, fmt.Errorf("sql/sqlclient: unknown driver %q. See: https://atlasgo.io/url", u.Scheme)
 	}
 	drv := v.(*driver)
 	// If there is a schema given and the driver allows to change the schema for the url, do it.


Test patch:
diff --git a/sql/sqlclient/client_test.go b/sql/sqlclient/client_test.go
index d9c45192..e5409654 100644
--- a/sql/sqlclient/client_test.go
+++ b/sql/sqlclient/client_test.go
@@ -57,7 +57,16 @@ func TestRegisterOpen(t *testing.T) {
 	require.Equal(t, "schema", c.URL.Schema)
 
 	c1, err = sqlclient.Open(context.Background(), "postgres://:3306")
-	require.EqualError(t, err, `sql/sqlclient: no opener was registered with name "postgres"`)
+	require.EqualError(t, err, `sql/sqlclient: unknown driver "postgres". See: https://atlasgo.io/url`)
+}
+
+func TestOpen_Errors(t *testing.T) {
+	c, err := sqlclient.Open(context.Background(), "missing")
+	require.EqualError(t, err, `sql/sqlclient: missing driver. See: https://atlasgo.io/url`)
+	require.Nil(t, c)
+	c, err = sqlclient.Open(context.Background(), "unknown://")
+	require.EqualError(t, err, `sql/sqlclient: unknown driver "unknown". See: https://atlasgo.io/url`)
+	require.Nil(t, c)
 }
 
 func TestClient_AddClosers(t *testing.T) {
Repository: ariga/atlas
Pull request #1401 (2023-01-12 12:24:00)

schemahcl: add url un/escape functions


Patch:
diff --git a/schemahcl/stdlib.go b/schemahcl/stdlib.go
index 0064f4ae..fdf990b5 100644
--- a/schemahcl/stdlib.go
+++ b/schemahcl/stdlib.go
@@ -156,6 +156,7 @@ func stdFuncs() map[string]function.Function {
 		"trimsuffix":      stdlib.TrimSuffixFunc,
 		"try":             tryfunc.TryFunc,
 		"upper":           stdlib.UpperFunc,
+		"urlescape":       urlEscape,
 		"urlqueryset":     urlQuerySetFunc,
 		"urlsetpath":      urlSetPathFunc,
 		"values":          stdlib.ValuesFunc,
@@ -288,3 +289,17 @@ var urlSetPathFunc = function.New(&function.Spec{
 		return cty.StringVal(u.String()), nil
 	},
 })
+
+var urlEscape = function.New(&function.Spec{
+	Params: []function.Parameter{
+		{
+			Name: "string",
+			Type: cty.String,
+		},
+	},
+	Type: function.StaticReturnType(cty.String),
+	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
+		u := url.QueryEscape(args[0].AsString())
+		return cty.StringVal(u), nil
+	},
+})


Test patch:
diff --git a/internal/integration/testdata/mysql/cli-project-url-escape.txt b/internal/integration/testdata/mysql/cli-project-url-escape.txt
new file mode 100644
index 00000000..9ec7b048
--- /dev/null
+++ b/internal/integration/testdata/mysql/cli-project-url-escape.txt
@@ -0,0 +1,36 @@
+only mysql8
+
+execsql 'CREATE USER IF NOT EXISTS "a8m"@"%" IDENTIFIED BY "&pass?"'
+execsql 'GRANT ALL PRIVILEGES ON *.* TO "a8m"@"%" WITH GRANT OPTION'
+
+atlas schema inspect --env local > got.txt
+cmp got.txt want.txt
+
+! atlas schema inspect --env failed
+stderr 'invalid port ":&pass" after host'
+
+execsql 'DROP USER "a8m"@"%"'
+
+-- atlas.hcl --
+variable "pass" {
+  type    = string
+  default = "&pass?"
+}
+
+locals {
+  escaped_pass = urlescape(var.pass)
+}
+
+env "local" {
+    url = "mysql://a8m:${local.escaped_pass}@localhost:3308/script_cli_project_url_escape"
+}
+
+env "failed" {
+    url = "mysql://a8m:${var.pass}@localhost:3308/script_cli_project_url_escape"
+}
+
+-- want.txt --
+schema "script_cli_project_url_escape" {
+  charset = "utf8mb4"
+  collate = "utf8mb4_0900_ai_ci"
+}
\ No newline at end of file
diff --git a/schemahcl/stdlib_test.go b/schemahcl/stdlib_test.go
index 0baaaa02..299b3ba2 100644
--- a/schemahcl/stdlib_test.go
+++ b/schemahcl/stdlib_test.go
@@ -6,6 +6,7 @@ package schemahcl
 
 import (
 	"fmt"
+	"net/url"
 	"testing"
 
 	"github.com/zclconf/go-cty/cty"
@@ -93,3 +94,17 @@ func TestURLQuerySetFunc(t *testing.T) {
 		})
 	}
 }
+
+func TestURLEscapeFunc(t *testing.T) {
+	for _, tt := range []string{"foo", "foo?", "foo&"} {
+		t.Run(tt, func(t *testing.T) {
+			got, err := urlEscape.Call([]cty.Value{cty.StringVal(tt)})
+			if err != nil {
+				t.Fatalf("unexpected error: %s", err)
+			}
+			if want := url.QueryEscape(tt); got.AsString() != want {
+				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, want)
+			}
+		})
+	}
+}
Repository: crsmithdev/arrow
Pull request #445 (2017-07-08 23:55:54)

add nepali locale support
I'm adding Nepali locale support as part of this PR. thanks!


Patch:
diff --git a/arrow/locales.py b/arrow/locales.py
index b5c8d5b..6e83af6 100644
--- a/arrow/locales.py
+++ b/arrow/locales.py
@@ -2046,4 +2046,50 @@ class IndonesianLocale(Locale):
     day_abbreviations = ['', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Minggu']
 
 
+class NepaliLocale(Locale):
+    names = ['ne', 'ne_np']
+
+    past = '{0} पहिले'
+    future = '{0} पछी'
+
+    timeframes = {
+        'now': 'अहिले',
+        'seconds': 'सेकण्ड',
+        'minute': 'मिनेट',
+        'minutes': '{0} मिनेट',
+        'hour': 'एक घण्टा',
+        'hours': '{0} घण्टा',
+        'day': 'एक दिन',
+        'days': '{0} दिन',
+        'month': 'एक महिना',
+        'months': '{0} महिना',
+        'year': 'एक बर्ष',
+        'years': 'बर्ष'
+    }
+
+    meridians = {
+        'am': 'पूर्वाह्न',
+        'pm': 'अपरान्ह',
+        'AM': 'पूर्वाह्न',
+        'PM': 'अपरान्ह'
+    }
+
+    month_names = [
+        '', 'जनवरी', 'फेब्रुअरी', 'मार्च', 'एप्रील', 'मे', 'जुन',
+        'जुलाई', 'अगष्ट', 'सेप्टेम्बर', 'अक्टोबर', 'नोवेम्बर', 'डिसेम्बर'
+    ]
+    month_abbreviations = [
+        '', 'जन', 'फेब', 'मार्च', 'एप्रील', 'मे', 'जुन', 'जुलाई', 'अग',
+        'सेप', 'अक्ट', 'नोव', 'डिस'
+    ]
+
+    day_names = [
+        '', 'सोमवार', 'मंगलवार', 'बुधवार', 'बिहिवार', 'शुक्रवार', 'शनिवार', 'आइतवार'
+    ]
+
+    day_abbreviations = [
+        '', 'सोम', 'मंगल', 'बुध', 'बिहि', 'शुक्र', 'शनि', 'आइत'
+    ]
+
+ 
 _locales = _map_locales()


Test patch:
diff --git a/tests/locales_tests.py b/tests/locales_tests.py
index 4f39419..e50d79f 100644
--- a/tests/locales_tests.py
+++ b/tests/locales_tests.py
@@ -554,6 +554,31 @@ class RomanianLocaleTests(Chai):
         self.assertEqual(self.locale._format_relative("o zi", "day", -1), "o zi în urmă")
         self.assertEqual(self.locale._format_relative("o zi", "day", 1), "peste o zi")
 
+
+class NepaliLocaleTests(Chai):
+
+    def setUp(self):
+        super(NepaliLocaleTests, self).setUp()
+
+        self.locale = locales.NepaliLocale()
+
+    def test_format_timeframe(self):
+        assertEqual(self.locale._format_timeframe('hours', 3), '3 घण्टा')
+        assertEqual(self.locale._format_timeframe('hour', 0), 'एक घण्टा')
+
+    def test_format_relative_now(self):
+        result = self.locale._format_relative('अहिले', 'now', 0)
+        assertEqual(result, 'अहिले')
+
+    def test_format_relative_future(self):
+        result = self.locale._format_relative('एक घण्टा', 'hour', 1)
+        assertEqual(result, 'एक घण्टा पछी')
+
+    def test_format_relative_past(self):
+        result = self.locale._format_relative('एक घण्टा', 'hour', -1)
+        assertEqual(result, 'एक घण्टा पहिले')
+
+
 class IndonesianLocaleTests(Chai):
 
     def setUp(self):
Repository: crsmithdev/arrow
Pull request #604 (2019-07-04 20:18:25)

Allow factory.get() to construct with kwargs
@jadchaar this is the small snippet of code I showed you a while back on zoom.

Essentially this lets us handle kwargs properly like the Arrow() constructor already does without having to do a ton of refactoring. Let me know if you think it's worth using as a quick fix.

```shell
arrow.get(year=2016, month=7, day=14)
<Arrow [2016-07-14T00:00:00+00:00]>
``` 

ref #415 


Patch:
diff --git a/arrow/factory.py b/arrow/factory.py
index 8591443..113b2c1 100644
--- a/arrow/factory.py
+++ b/arrow/factory.py
@@ -137,6 +137,13 @@ class ArrowFactory(object):
         locale = kwargs.get("locale", "en_us")
         tz = kwargs.get("tzinfo", None)
 
+        # if kwargs given, send to constructor unless only tzinfo provided.
+        if len(kwargs) > 1:
+            arg_count = 3
+        if len(kwargs) == 1:
+            if not isinstance(tz, tzinfo):
+                arg_count = 3
+
         # () -> now, @ utc.
         if arg_count == 0:
             if isinstance(tz, tzinfo):


Test patch:
diff --git a/tests/factory_tests.py b/tests/factory_tests.py
index 21e5ae4..416530e 100644
--- a/tests/factory_tests.py
+++ b/tests/factory_tests.py
@@ -221,6 +221,46 @@ class GetTests(Chai):
             self.factory.get(2013, 1, 1), datetime(2013, 1, 1, tzinfo=tz.tzutc())
         )
 
+    def test_full_kwargs(self):
+
+        self.assertEqual(
+            self.factory.get(
+                year=2016,
+                month=7,
+                day=14,
+                hour=7,
+                minute=16,
+                second=45,
+                microsecond=631092,
+            ),
+            datetime(2016, 7, 14, 7, 16, 45, 631092, tzinfo=tz.tzutc()),
+        )
+
+    def test_three_kwargs(self):
+
+        self.assertEqual(
+            self.factory.get(year=2016, month=7, day=14),
+            datetime(2016, 7, 14, 0, 0, tzinfo=tz.tzutc()),
+        )
+
+    def test_insufficient_kwargs(self):
+
+        with self.assertRaises(TypeError):
+            self.factory.get(year=2016)
+
+        with self.assertRaises(TypeError):
+            self.factory.get(year=2016, month=7)
+
+    def test_locale_kwarg_only(self):
+
+        with self.assertRaises(TypeError):
+            self.factory.get(locale="ja")
+
+    def test_locale_with_tzinfo(self):
+
+        with self.assertRaises(TypeError):
+            self.factory.get(locale="ja", tzinfo=tz.gettz("Asia/Tokyo"))
+
 
 class UtcNowTests(Chai):
     def setUp(self):
Repository: crsmithdev/arrow
Pull request #610 (2019-07-12 23:04:33)

Add meridians to Spanish locale
```shell
arrow.get('Junio 30, 2019 - 08:00 pm', "MMMM DD, YYYY - hh:mm a", locale="es")
<Arrow [2019-06-30T20:00:00+00:00]>
```

/cc @NestorTejero
ref #607 


Patch:
diff --git a/arrow/locales.py b/arrow/locales.py
index 5a09e5b..99c171e 100644
--- a/arrow/locales.py
+++ b/arrow/locales.py
@@ -376,6 +376,8 @@ class SpanishLocale(Locale):
         "years": "{0} años",
     }
 
+    meridians = {"am": "am", "pm": "pm", "AM": "AM", "PM": "PM"}
+
     month_names = [
         "",
         "enero",


Test patch:
diff --git a/tests/parser_tests.py b/tests/parser_tests.py
index a212f04..0ecd13a 100644
--- a/tests/parser_tests.py
+++ b/tests/parser_tests.py
@@ -727,6 +727,15 @@ class DateTimeParserMeridiansTests(Chai):
             parser_.parse("2013-01-01 5 DU", "YYYY-MM-DD h A"), datetime(2013, 1, 1, 17)
         )
 
+    # regression check for https://github.com/crsmithdev/arrow/issues/607
+    def test_es_meridians(self):
+        parser_ = parser.DateTimeParser("es")
+
+        self.assertEqual(
+            parser_.parse("Junio 30, 2019 - 08:00 pm", "MMMM DD, YYYY - hh:mm a"),
+            datetime(2019, 6, 30, 20, 0),
+        )
+
 
 class DateTimeParserMonthOrdinalDayTests(Chai):
     def setUp(self):
Repository: crsmithdev/arrow
Pull request #620 (2019-07-29 03:34:01)

Move backports from extra_requires to install_requires
This is now the official method for conditionally requiring python versions as documented here: https://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies. Pytest does the same here: https://github.com/pytest-dev/pytest/blob/master/setup.py#L11.

Addresses: https://github.com/crsmithdev/arrow/issues/495


Patch:
diff --git a/arrow/factory.py b/arrow/factory.py
index ba705d3..fc06208 100644
--- a/arrow/factory.py
+++ b/arrow/factory.py
@@ -157,7 +157,7 @@ class ArrowFactory(object):
         if len(kwargs) > 1:
             arg_count = 3
         if len(kwargs) == 1:
-            if not isinstance(tz, tzinfo):
+            if not tz:
                 arg_count = 3
 
         # () -> now, @ utc.
diff --git a/setup.py b/setup.py
index c1e2b65..dec463a 100644
--- a/setup.py
+++ b/setup.py
@@ -13,7 +13,7 @@ with io.open("arrow/_version.py", "r", encoding="utf-8") as f:
 setup(
     name="arrow",
     version=about["__version__"],
-    description="Better dates and times for Python",
+    description="Better dates & times for Python",
     long_description=readme,
     long_description_content_type="text/x-rst",
     url="https://arrow.readthedocs.io/en/latest/",
@@ -23,8 +23,10 @@ setup(
     packages=["arrow"],
     zip_safe=False,
     python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
-    install_requires=["python-dateutil"],
-    extras_require={":python_version=='2.7'": ["backports.functools_lru_cache>=1.2.1"]},
+    install_requires=[
+        "python-dateutil",
+        "backports.functools_lru_cache>=1.2.1;python_version=='2.7'",
+    ],
     test_suite="tests",
     tests_require=["chai"],
     classifiers=[
@@ -40,7 +42,7 @@ setup(
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
     ],
-    keywords="arrow date time datetime",
+    keywords="arrow date time datetime timestamp timezone",
     project_urls={
         "Repository": "https://github.com/crsmithdev/arrow",
         "Bug Reports": "https://github.com/crsmithdev/arrow/issues",


Test patch:
diff --git a/tests/factory_tests.py b/tests/factory_tests.py
index 416530e..635f0d0 100644
--- a/tests/factory_tests.py
+++ b/tests/factory_tests.py
@@ -243,6 +243,12 @@ class GetTests(Chai):
             datetime(2016, 7, 14, 0, 0, tzinfo=tz.tzutc()),
         )
 
+    def test_tzinfo_string_kwargs(self):
+        result = self.factory.get("2019072807", "YYYYMMDDHH", tzinfo="UTC")
+        self.assertEqual(
+            result._datetime, datetime(2019, 7, 28, 7, 0, 0, 0, tzinfo=tz.tzutc())
+        )
+
     def test_insufficient_kwargs(self):
 
         with self.assertRaises(TypeError):
Repository: crsmithdev/arrow
Pull request #621 (2019-07-29 17:10:38)

Fix regression when tzinfo kwarg is a string
In v 0.14.2 passing a date string, a format string and tzinfo kwarg where the value is a string worked correctly. This usage pattern broke in 0.14.3. This restores the previous behavior.


Patch:
diff --git a/arrow/factory.py b/arrow/factory.py
index ba705d3..fc06208 100644
--- a/arrow/factory.py
+++ b/arrow/factory.py
@@ -157,7 +157,7 @@ class ArrowFactory(object):
         if len(kwargs) > 1:
             arg_count = 3
         if len(kwargs) == 1:
-            if not isinstance(tz, tzinfo):
+            if not tz:
                 arg_count = 3
 
         # () -> now, @ utc.


Test patch:
diff --git a/tests/factory_tests.py b/tests/factory_tests.py
index 416530e..635f0d0 100644
--- a/tests/factory_tests.py
+++ b/tests/factory_tests.py
@@ -243,6 +243,12 @@ class GetTests(Chai):
             datetime(2016, 7, 14, 0, 0, tzinfo=tz.tzutc()),
         )
 
+    def test_tzinfo_string_kwargs(self):
+        result = self.factory.get("2019072807", "YYYYMMDDHH", tzinfo="UTC")
+        self.assertEqual(
+            result._datetime, datetime(2019, 7, 28, 7, 0, 0, 0, tzinfo=tz.tzutc())
+        )
+
     def test_insufficient_kwargs(self):
 
         with self.assertRaises(TypeError):
Repository: crsmithdev/arrow
Pull request #663 (2019-09-10 16:21:15)

0.15.0 regression - Support negative numbers in the timestamp regular expression
This solves https://github.com/crsmithdev/arrow/issues/662

Currently arrow does not allow you to pass in negative numbers for seconds relative to epoch when using strings. This patch is an attempt to fix this.


Patch:
diff --git a/arrow/parser.py b/arrow/parser.py
index f1469a0..2720d3c 100644
--- a/arrow/parser.py
+++ b/arrow/parser.py
@@ -45,7 +45,7 @@ class DateTimeParser(object):
     _TZ_NAME_RE = re.compile(r"\w[\w+\-/]+")
     # NOTE: timestamps cannot be parsed from natural language strings (by removing the ^...$) because it will
     # break cases like "15 Jul 2000" and a format list (see issue #447)
-    _TIMESTAMP_RE = re.compile(r"^\d+\.?\d+$")
+    _TIMESTAMP_RE = re.compile(r"^-?\d+\.?\d+$")
     _TIME_RE = re.compile(r"^(\d{2})(?:\:?(\d{2}))?(?:\:?(\d{2}))?(?:([\.\,])(\d+))?$")
 
     _BASE_INPUT_RE_MAP = {


Test patch:
diff --git a/tests/parser_tests.py b/tests/parser_tests.py
index 36bafcc..0fe7543 100644
--- a/tests/parser_tests.py
+++ b/tests/parser_tests.py
@@ -224,6 +224,12 @@ class DateTimeParserParseTests(Chai):
             self.parser.parse("{:f}123456".format(float_timestamp), "X"), self.expected
         )
 
+        negative_timestamp = -1565358758
+        self.expected = datetime.fromtimestamp(negative_timestamp, tz=tz_utc)
+        self.assertEqual(
+            self.parser.parse("{:d}".format(negative_timestamp), "X"), self.expected
+        )
+
         # NOTE: timestamps cannot be parsed from natural language strings (by removing the ^...$) because it will
         # break cases like "15 Jul 2000" and a format list (see issue #447)
         with self.assertRaises(ParserError):